The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*
Copyright (C) 2001-2011, Parrot Foundation.

=head1 NAME

src/pmc/stringiterator.pmc - StringIterator PMC

=head1 DESCRIPTION

Implementation of Iterator for String PMC.

=head1 SYNOPSIS


=head1 Methods

=over 4

=cut

*/


/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */

pmclass StringIterator auto_attrs extends Iterator provides iterator {
    ATTR STRING      *str_val;   /* String to iterate over */
    ATTR String_iter  iter;      /* String iterator */
    ATTR INTVAL       reverse;   /* Direction of iteration. 1 - for reverse iteration */

/*

=item C<void init_pmc()>

Initialize StringIterator.

=cut

*/
    VTABLE void init_pmc(PMC *string) {
        String_iter * const iter    = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING      * const str_val = VTABLE_get_string(INTERP, string);

        SET_ATTR_str_val(INTERP, SELF, str_val);
        STRING_ITER_INIT(INTERP, iter);
        SET_ATTR_reverse(INTERP, SELF, ITERATE_FROM_START);

        PObj_custom_mark_SET(SELF);
    }

/*

=item C<void mark()>

Marks the current idx/key and the aggregate as live.

=cut

*/

    VTABLE void mark() {
        STRING *str_val;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        Parrot_gc_mark_STRING_alive(INTERP, str_val);
    }

/*

=item C<PMC *clone()>

=cut

*/
    VTABLE PMC* clone() {
        String_iter * const iter    = &PARROT_STRINGITERATOR(SELF)->iter;
        PMC         * const str_pmc = Parrot_pmc_new(INTERP, enum_class_String);
        PMC         *clone;
        String_iter *clone_iter;
        STRING      *str_val;
        INTVAL       reverse;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        VTABLE_set_string_native(INTERP, str_pmc, str_val);
        clone = Parrot_pmc_new_init(INTERP, enum_class_StringIterator, str_pmc);
        clone_iter = &PARROT_STRINGITERATOR(clone)->iter;
        *clone_iter = *iter;
        GET_ATTR_reverse(INTERP, SELF, reverse);
        SET_ATTR_reverse(INTERP, clone, reverse);

        return clone;
    }

/*

=item C<INTVAL get_bool()>

Returns true if there is more elements to iterate over.

=cut

*/

    VTABLE INTVAL get_bool() {
        return SELF.elements() > 0;
    }

/*

=item C<INTVAL elements()>

Returns the number of remaining elements in the C<string>.

=cut

*/

    VTABLE INTVAL elements() {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING *str_val;
        INTVAL  reverse;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        GET_ATTR_reverse(INTERP, SELF, reverse);

        if (reverse)
            return iter->charpos;
        else
            return str_val->strlen - iter->charpos;
    }

    VTABLE INTVAL get_integer() {
        return SELF.elements();
    }

/*

=item C<void set_integer_native(INTVAL value)>

Reset the Iterator. C<value> must be one of

 ITERATE_FROM_START        ... Iterate from start
 ITERATE_FROM_END          ... Iterate from end

=cut

*/

    VTABLE void set_integer_native(INTVAL value) {
        STRING *str_val;
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        if (value == ITERATE_FROM_START) {
            SET_ATTR_reverse(INTERP, SELF, 0);
            STRING_ITER_INIT(INTERP, iter);
        }
        else if (value == ITERATE_FROM_END) {
            SET_ATTR_reverse(INTERP, SELF, 1);
            iter->bytepos = str_val->bufused;
            iter->charpos = str_val->strlen;
        }
        else {
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                    "Wrong direction for StringIterator");
        }
    }

/*

=item C<PMC *get_pmc()>

Returns this Iterator's string.

=cut

*/

    VTABLE PMC *get_pmc() {
        PMC * const string = Parrot_pmc_new(INTERP, Parrot_hll_get_ctx_HLL_type(
            interp, enum_class_String));
        STRING *str_val;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        VTABLE_set_string_native(interp, string, str_val);
        return string;
    }

/*

=item C<STRING *shift_pmc()>

Shift next character from C<string> as PMC.

=cut

*/
    VTABLE PMC *shift_pmc() {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        PMC *ret;
        STRING *str_val, *substr;
        const String_iter old_iter = *iter;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        if (iter->charpos >= str_val->strlen)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        ret = Parrot_pmc_new(INTERP, Parrot_hll_get_ctx_HLL_type(interp, enum_class_String));
        STRING_iter_skip(INTERP, str_val, iter, 1);
        substr = Parrot_str_iter_substr(INTERP, str_val, &old_iter, iter);
        VTABLE_set_string_native(INTERP, ret, substr);
        return ret;
    }

/*

=item C<STRING *shift_string()>

Shift next character from C<string>.

=cut

*/
    VTABLE STRING *shift_string() {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING *str_val;
        const String_iter old_iter = *iter;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        if (iter->charpos >= str_val->strlen)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        STRING_iter_skip(INTERP, str_val, iter, 1);
        return Parrot_str_iter_substr(INTERP, str_val, &old_iter, iter);
    }

/*

=item C<INTVAL shift_integer()>

Shift next character code from C<string>.

=cut

*/
    VTABLE INTVAL shift_integer() {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING *str_val;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        if (iter->charpos >= str_val->strlen)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        return STRING_iter_get_and_advance(INTERP, str_val, iter);
    }

/*

=item C<STRING *pop_pmc()>

Shift "next" character from C<string> for reverse iterator as PMC.

=cut

*/
    VTABLE PMC *pop_pmc() {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING *str_val, *substr;
        PMC *ret;
        const String_iter old_iter = *iter;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        /* Shouldn't this test be (iter->charpos <= 0) ? */
        if (SELF.elements() <= 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        ret = Parrot_pmc_new(INTERP, Parrot_hll_get_ctx_HLL_type(interp, enum_class_String));
        STRING_iter_skip(INTERP, str_val, iter, -1);
        substr = Parrot_str_iter_substr(INTERP, str_val, iter, &old_iter);
        VTABLE_set_string_native(INTERP, ret, substr);
        return ret;
    }

/*

=item C<STRING *pop_string()>

Shift "next" character from C<string> for reverse iterator.

=cut

*/
    VTABLE STRING *pop_string() {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING *str_val;
        const String_iter old_iter = *iter;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        /* Shouldn't this test be (iter->charpos <= 0) ? */
        if (SELF.elements() <= 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        STRING_iter_skip(INTERP, str_val, iter, -1);
        return Parrot_str_iter_substr(INTERP, str_val, iter, &old_iter);
    }

/*

=item C<INTVAL pop_integer()>

Shift "next" character code from C<string> for reverse iterator.

=cut

*/
    VTABLE INTVAL pop_integer() {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING *str_val;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        /* Shouldn't this test be (iter->charpos <= 0) ? */
        if (SELF.elements() <= 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        STRING_iter_skip(INTERP, str_val, iter, -1);
        return STRING_iter_get(INTERP, str_val, iter, 0);
    }

/*

=item C<INTVAL get_integer_keyed_int(INTVAL idx)>

Get integer value of current position plus idx.

=cut

*/

    VTABLE INTVAL get_integer_keyed_int(INTVAL idx) {
        String_iter * const iter = &PARROT_STRINGITERATOR(SELF)->iter;
        STRING *str_val;
        const UINTVAL offset = iter->charpos + idx;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        if (offset >= str_val->strlen)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        return STRING_iter_get(INTERP, str_val, iter, idx);
    }

/*

=item C<STRING *get_string_keyed_int(INTVAL idx)>

Get string value of current position plus idx.

=cut

*/

    VTABLE STRING *get_string_keyed_int(INTVAL idx) {
        String_iter iter = PARROT_STRINGITERATOR(SELF)->iter;
        String_iter next_iter;
        STRING *str_val;
        const UINTVAL offset = iter.charpos + idx;

        GET_ATTR_str_val(INTERP, SELF, str_val);
        if (offset >= str_val->strlen)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "StopIteration");

        if (idx != 0)
            STRING_iter_skip(INTERP, str_val, &iter, idx);
        next_iter = iter;
        STRING_iter_skip(INTERP, str_val, &next_iter, 1);

        return Parrot_str_iter_substr(INTERP, str_val, &iter, &next_iter);
    }
}


/*

=back

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
 */