tagged release 0.6.4
[parrot.git] / src / pmc / iterator.pmc
blob61267fa99ce152fc5b196f09a8209d0248c8afcd
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/iterator.pmc - Iterator PMC
9 =head1 DESCRIPTION
11 These are the vtable functions for the Iterator base class. Iterators are
12 used in combination with other classes(mainly aggregates) to visit all entries
13 in that aggregate.
15 =head1 SYNOPSIS
17 =head2 default usage
19     .local pmc iterator, array, entry
20     iterator = new 'Iterator', array
21   iter_loop:
22     unless iterator, iter_end  # while (more values)
23     entry = shift iterator     # get an entry
24     ...
25     goto iter_loop
26   iter_end:
28 The C<new> can alteratively be written as:
30   iterator = iter array
32 =head2 iterate from the end, for arrays
34     .local pmc iterator, array, entry
35     iterator = new 'Iterator', array
36     iterator = .ITERATE_FROM_END
37   iter_loop:
38     unless iterator, iter_end  # while (more values)
39     entry = pop iterator     # get an entry
40     ...
41     goto iter_loop
42   iter_end:
44 =head2 iterate over a hash
46     .local pmc iterator, hash, key, entry
47     iterator = new 'Iterator', hash
48   iter_loop:
49     unless iterator, iter_end  # while (more values)
50     key   = shift iterator     # get the key..
51     entry = hash[key]
52     ...
53     goto iter_loop
54   iter_end:
56 =head1 Methods
58 =over 4
60 =cut
64 #include "parrot/parrot.h"
66 pmclass Iterator no_ro {
68     void class_init() {
69         if (pass) {
70             /* Make the shift_pmc vtable function available as
71              * a method named "next" */
72             register_nci_method(INTERP, enum_class_Iterator,
73                     F2DPTR(Parrot_Iterator_shift_pmc), "next", "PJO");
74         }
75     }
79 =item C<void init()>
81 Raises an exception. Use C<init_pmc()>.
83 =cut
87     VTABLE void init() {
88         real_exception(INTERP, NULL, E_Exception,
89                 "Iterator init without aggregate");
90     }
94 =item C<void init_pmc(PMC *initializer)>
96 Initializes the iterator with an aggregate PMC.
97 Defaults iteration mode to iterate from start.
99 =cut
103     VTABLE void init_pmc(PMC *aggregate) {
104         PMC_pmc_val(SELF)    = aggregate;
105         PMC_struct_val(SELF) = NULL;
106         PObj_custom_mark_SET(SELF);
108         /* by default, iterate from start */
109         SELF.set_integer_native(ITERATE_FROM_START);
110     }
114 =item C<void mark()>
116 Marks the current idx/key and the aggregate as live.
118 =cut
122     VTABLE void mark() {
123         /* the KEY */
124         if (PMC_struct_val(SELF))
125              pobject_lives(INTERP, (PObj *)PMC_struct_val(SELF));
127         /* the aggregate */
128         if (PMC_pmc_val(SELF))
129              pobject_lives(INTERP, (PObj *)PMC_pmc_val(SELF));
130     }
134 =item C<PMC *clone()>
136 Make a clone of the iterator.
138 =cut
142     VTABLE PMC *clone() {
143         PMC * const key     = (PMC *)PMC_struct_val(SELF);
144         PMC * const res     = pmc_new_init(INTERP, SELF->vtable->base_type,
145                                            PMC_pmc_val(SELF));
146         PMC_struct_val(res) = VTABLE_clone(interp, key);
147         return res;
148     }
152 =item C<INTVAL get_integer()>
154 Get number of remaining elements. Does not work for hashes yet.
155 TODO: keep track of current position and direction
157 =cut
161     VTABLE INTVAL get_integer() {
162         return SELF.elements();
163     }
167 =item C<STRING *get_string()>
169 Returns a textual representation of the iterator.
171 =cut
175     VTABLE STRING *get_string() {
176         PMC * const key = (PMC *)PMC_struct_val(SELF);
177         return string_from_int(INTERP, key_integer(INTERP, key));
178     }
182 =item C<INTVAL get_integer_keyed(PMC *key)>
184 =cut
188     VTABLE INTVAL get_integer_keyed(PMC *key) {
189         return VTABLE_get_integer_keyed(INTERP, PMC_pmc_val(SELF), key);
190     }
194 =item C<INTVAL get_integer_keyed_int(INTVAL idx)>
196 Get integer value of current position plus idx.
198 =cut
202     VTABLE INTVAL get_integer_keyed_int(INTVAL idx) {
203         PMC * const key = (PMC *)PMC_struct_val(SELF);
204         PMC * const agg = PMC_pmc_val(SELF);
205         return VTABLE_get_integer_keyed_int(INTERP, agg, PMC_int_val(key) +idx);
206     }
210 =item C<FLOATVAL get_number_keyed(PMC *key)>
212 =cut
216     VTABLE FLOATVAL get_number_keyed(PMC *key) {
217         return VTABLE_get_number_keyed(INTERP, PMC_pmc_val(SELF), key);
218     }
222 =item C<FLOATVAL get_number_keyed_int(INTVAL idx)>
224 Get number value of current position plus idx.
226 =cut
230     VTABLE FLOATVAL get_number_keyed_int(INTVAL idx) {
231         PMC * const key = (PMC *)PMC_struct_val(SELF);
232         PMC * const agg = PMC_pmc_val(SELF);
233         return VTABLE_get_number_keyed_int(INTERP, agg, PMC_int_val(key) + idx);
234     }
240 =item C<STRING *get_string_keyed(PMC *key)>
242 =cut
246     VTABLE STRING *get_string_keyed(PMC *key) {
247         return VTABLE_get_string_keyed(INTERP, PMC_pmc_val(SELF), key);
248     }
252 =item C<STRING *get_string_keyed_int(INTVAL idx)>
254 Get string value of current position plus idx.
256 =cut
260     VTABLE STRING *get_string_keyed_int(INTVAL idx) {
261         PMC * const key = (PMC *)PMC_struct_val(SELF);
262         PMC * const agg = PMC_pmc_val(SELF);
263         return VTABLE_get_string_keyed_int(INTERP, agg, PMC_int_val(key) + idx);
264     }
268 =item C<INTVAL get_bool()>
270 Returns true if the idx/key is not C<-1>.
272 =cut
276     VTABLE INTVAL get_bool() {
277         PMC * const key = (PMC *)PMC_struct_val(SELF);
278         return key && PMC_int_val(key) != -1;
279     }
283 =item C<INTVAL elements()>
285 Returns the number of remaining elements in the aggregate. TODO.
287 =cut
291     VTABLE INTVAL elements() {
292         return VTABLE_elements(INTERP, PMC_pmc_val(SELF));
293     }
297 =item C<PMC *get_pmc_keyed(PMC *key)>
299 Returns the element for C<*key>.
301 =cut
305     VTABLE PMC *get_pmc_keyed(PMC *key) {
306         return VTABLE_get_pmc_keyed(INTERP, PMC_pmc_val(SELF), key);
307     }
311 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
313 Returns the element for C<key>.
315 =cut
319     VTABLE PMC *get_pmc_keyed_int(INTVAL idx) {
320         PMC * const key = (PMC *)PMC_struct_val(SELF);
321         PMC * const agg = PMC_pmc_val(SELF);
322         return VTABLE_get_pmc_keyed_int(INTERP, agg, PMC_int_val(key) + idx);
323     }
327 =item C<void set_integer_native(INTVAL value)>
329 Reset the Iterator. C<value> must be one of
331  ITERATE_FROM_START        ... Iterate from start
332  ITERATE_FROM_START_KEYS   ... OrderedHash by keys
333  ITERATE_FROM_END          ... Arrays and PerlString only
335 =cut
339     VTABLE void set_integer_native(INTVAL value) {
340         PMC *key, *agg;
341         if (value < ITERATE_FROM_START || value > ITERATE_FROM_END)
342             real_exception(INTERP, NULL, E_TypeError,
343                     "Illegal set_integer on iterator");
345         /* reset iterator on aggregate */
346         agg = PMC_pmc_val(SELF);
348         if (agg->vtable->base_type == enum_class_Slice) {
349             /* it's an xrange serving as its own aggregate */
350             PMC_struct_val(SELF) =
351                 VTABLE_nextkey_keyed(INTERP, agg, NULL, value);
352         }
353         else {
354             if (!PMC_struct_val(SELF))
355                 key = key_new(INTERP);
356             else
357                 key = (PMC *)PMC_struct_val(SELF);
359             PMC_struct_val(SELF) =
360                 VTABLE_nextkey_keyed(INTERP, key, agg, value);
361         }
362     }
366 =item C<INTVAL pop_integer()>
368 =cut
372     VTABLE INTVAL pop_integer() {
373         PMC * const key      = (PMC *)PMC_struct_val(SELF);
374         PMC * const agg      = PMC_pmc_val(SELF);
375         const INTVAL ret     = VTABLE_get_integer_keyed(INTERP, agg, key);
376         PMC_struct_val(SELF) =
377             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_PREV);
379         return ret;
380     }
384 =item C<FLOATVAL pop_float()>
386 =cut
390     VTABLE FLOATVAL pop_float() {
391         PMC * const key      = (PMC *)PMC_struct_val(SELF);
392         PMC * const agg      = PMC_pmc_val(SELF);
393         const FLOATVAL ret   = VTABLE_get_number_keyed(INTERP, agg, key);
394         PMC_struct_val(SELF) =
395             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_PREV);
397         return ret;
398     }
402 =item C<STRING *pop_string()>
404 =cut
408     VTABLE STRING *pop_string() {
409         PMC * const key      = (PMC *)PMC_struct_val(SELF);
410         PMC * const agg      = PMC_pmc_val(SELF);
411         STRING * const ret   = VTABLE_get_string_keyed(INTERP, agg, key);
412         PMC_struct_val(SELF) =
413             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_PREV);
414         return ret;
415     }
419 =item C<PMC *pop_pmc()>
421 Returns the element for the current idx/key and sets the idx/key to
422 the previous one.
424 =cut
428     VTABLE PMC *pop_pmc() {
429         PMC * const key      = (PMC *)PMC_struct_val(SELF);
430         PMC * const agg      = PMC_pmc_val(SELF);
431         PMC * const ret      = VTABLE_get_pmc_keyed(INTERP, agg, key);
432         PMC_struct_val(SELF) =
433             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_PREV);
435         return ret;
436     }
440 =item C<INTVAL shift_integer()>
442 Returns the element for the current idx/key and sets the idx/key to
443 the next one.
445 =cut
449     VTABLE INTVAL shift_integer() {
450         PMC * const key      = (PMC *)PMC_struct_val(SELF);
451         PMC * const agg      = PMC_pmc_val(SELF);
452         const INTVAL ret     = VTABLE_get_integer_keyed(INTERP, agg, key);
453         PMC_struct_val(SELF) =
454             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_NEXT);
455         return ret;
456     }
460 =item C<opcode_t *invoke(void *next)>
462 Return the next element of the aggregate. The return type may depend on
463 the aggregate. If there are no more items in the aggregate, I1 .. I4 are
464 zero.
466 See F<docs/pdds/pdd03_calling_conventions.pod>.
468 =cut
471     VTABLE opcode_t *invoke(void *next) {
472         PMC *agg;
474         /* iterator constructor */
475         if (REG_INT(interp, 3) == 1) {
476             PMC *arg = REG_PMC(interp, 5);
477             PMC *iter;
479             if (PObj_is_object_TEST(arg)) {
480                 REG_PMC(interp, 5) = VTABLE_get_iter(INTERP, arg);
481                 return (opcode_t *)next;
482             }
484             REG_PMC(interp, 5) = iter = pmc_new_init(INTERP,
485                     enum_class_Iterator, arg);
486             VTABLE_set_integer_native(INTERP, iter, 0);
487             return (opcode_t *)next;
488         }
489         /* TODO function + sentinel */
490         else if (REG_INT(interp, 3) == 2)
491             real_exception(INTERP, NULL, E_AssertionError,
492                     "Iterator: invoke 2 args");
494         REG_INT(interp, 1) =
495             REG_INT(interp, 2) =
496             REG_INT(interp, 3) =
497             REG_INT(interp, 4) = 0;
499         agg        = PMC_pmc_val(SELF);
501         if (agg->vtable->base_type == enum_class_IntList) {
502             const INTVAL ires  = SELF.shift_integer();
503             REG_INT(interp, 1) = 1;
504             REG_INT(interp, 5) = ires;
505             return (opcode_t *)next;
506         }
507         else {
508             PMC * const res    = SELF.shift_pmc();
509             REG_INT(interp, 3) = 1;
510             REG_PMC(interp, 5) = res;
511             return (opcode_t *)next;
512         }
513     }
517 =item C<FLOATVAL shift_float()>
519 =cut
523     VTABLE FLOATVAL shift_float() {
524         PMC * const key      = (PMC *)PMC_struct_val(SELF);
525         PMC * const agg      = PMC_pmc_val(SELF);
526         const FLOATVAL ret   = VTABLE_get_number_keyed(INTERP, agg, key);
527         PMC_struct_val(SELF) =
528             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_NEXT);
529         return ret;
530     }
535 =item C<STRING *shift_string()>
537 =cut
541     VTABLE STRING *shift_string() {
542         PMC * const key      = (PMC *)PMC_struct_val(SELF);
543         PMC * const agg      = PMC_pmc_val(SELF);
544         STRING * const ret   = VTABLE_get_string_keyed(INTERP, agg, key);
545         PMC_struct_val(SELF) =
546             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_NEXT);
547         return ret;
548     }
552 =item C<PMC *shift_pmc()>
554 Returns the element for the current idx/key and sets the idx/key to
555 the next one.
557 =cut
561     VTABLE PMC *shift_pmc() {
562         PMC * const key = (PMC *)PMC_struct_val(SELF);
563         PMC * const agg = PMC_pmc_val(SELF);
564         PMC        *ret;
566         if (PMC_int_val(key) == -1)
567             real_exception(INTERP, NULL, E_StopIteration, "StopIteration");
569         ret = VTABLE_get_pmc_keyed(INTERP, agg, key);
571         PMC_struct_val(SELF) =
572             VTABLE_nextkey_keyed(INTERP, key, agg, ITERATE_GET_NEXT);
574         return ret;
575     }
579 =item C<INTVAL exists_keyed(PMC *key)>
581 Returns whether an element for C<*key> exists in the aggregate.
583 =cut
587     VTABLE INTVAL exists_keyed(PMC *key) {
588         return VTABLE_exists_keyed(INTERP, PMC_pmc_val(SELF), key);
589     }
593 =item C<INTVAL exists_keyed_int(INTVAL idx)>
595 Returns whether an element for C<idx> exists in the aggregate.
597 =cut
601     VTABLE INTVAL exists_keyed_int(INTVAL idx) {
602         PMC * const key = (PMC *)PMC_struct_val(SELF);
603         PMC * const agg = PMC_pmc_val(SELF);
604         return VTABLE_exists_keyed_int(INTERP, agg, PMC_int_val(key) + idx);
605     }
609 =item C<INTVAL defined()>
611 Returns whether the iterator contains an aggregate.
613 =cut
617     VTABLE INTVAL defined() {
618         return (INTVAL)(PMC_pmc_val(SELF) != 0);
619     }
623 =item C<INTVAL defined_keyed(PMC *key)>
625 =cut
629     VTABLE INTVAL defined_keyed(PMC *key) {
630         return VTABLE_defined_keyed(INTERP, PMC_pmc_val(SELF), key);
631     }
635 =item C<INTVAL defined_keyed_int(INTVAL key)>
637 Returns the result of calling C<defined_keyed(key)> on the aggregate.
639 =cut
643     VTABLE INTVAL defined_keyed_int(INTVAL idx) {
644         PMC * const key = (PMC *)PMC_struct_val(SELF);
645         PMC * const agg = PMC_pmc_val(SELF);
646         return VTABLE_defined_keyed_int(INTERP, agg, PMC_int_val(key) + idx);
647     }
651 =item C<INTVAL type_keyed(PMC *key)>
653 Returns the result of calling C<type_keyed(key)> on the aggregate.
655 =cut
659     VTABLE INTVAL type_keyed(PMC *key) {
660         return VTABLE_type_keyed(INTERP, PMC_pmc_val(SELF), key);
661     }
665 =item C<INTVAL type_keyed_int(PMC *idx)>
667 Returns the result of calling C<type_keyed(key)> on the aggregate.
669 =cut
673     VTABLE INTVAL type_keyed_int(INTVAL idx) {
674         PMC * const key = (PMC *)PMC_struct_val(SELF);
675         PMC * const agg = PMC_pmc_val(SELF);
676         return VTABLE_type_keyed_int(INTERP, agg, PMC_int_val(key) + idx);
677     }
679     VTABLE PMC *get_iter() {
680         return SELF;
681     }
686 =back
688 =cut
693  * Local variables:
694  *   c-file-style: "parrot"
695  * End:
696  * vim: expandtab shiftwidth=4:
697  */