package Range::ArrayIter;

our $DATE = '2019-04-23'; # DATE
our $VERSION = '0.002'; # VERSION

use strict;
use warnings;

use Exporter qw(import);
our @EXPORT_OK = qw(range_arrayiter);

sub range_arrayiter($$;$) {
    my ($start, $end, $step) = @_;

    tie my @ary, 'Range::ArrayIter::Tie', $start, $end, $step;
    \@ary;
}

package # hide from PAUSE
    Range::ArrayIter::Tie;

use Scalar::Util qw(looks_like_number);

sub TIEARRAY {
    my $class = shift;
    my ($start, $end, $step) = @_;
    $step //= 1;

    my $self = {
        start => $start,
        end   => $end,
        step  => $step,

        _ended => 0,
        _len   => 0,
        _cur   => $start,
        _buf   => [],
    };

    if (looks_like_number($start) && looks_like_number($end)) {
        $self->{_num}   = 1;
        $self->{_ended}++ if $start > $end;
    } else {
        die "Cannot specify step != 1 for non-numeric range" if $step != 1;
        $self->{_ended}++ if $start gt $end;
    }
    bless $self, $class;
}

sub _next {
    my $self = shift;

    if ($self->{_num}) {
        $self->{_ended}++ if $self->{_cur} > $self->{end};
        return if $self->{_ended};
        push @{ $self->{_buf} }, $self->{_cur};
        $self->{_cur} += $self->{step};
    } else {
        return if $self->{_ended};
        $self->{_ended}++ if $self->{_cur} ge $self->{end};
        push @{ $self->{_buf} }, $self->{_cur}++;
    }
}

sub FETCHSIZE {
    my $self = shift;
    $self->_next;
    $self->{_len} + @{ $self->{_buf} };
}

sub FETCH {
    my $self = shift;
    if (@{ $self->{_buf} }) {
        $self->{_len}++;
        shift @{ $self->{_buf} };
    } else {
        undef;
    }
}

1;
# ABSTRACT: Generate a tied-array iterator for range

__END__

=pod

=encoding UTF-8

=head1 NAME

Range::ArrayIter - Generate a tied-array iterator for range

=head1 VERSION

This document describes version 0.002 of Range::ArrayIter (from Perl distribution Range-ArrayIter), released on 2019-04-23.

=head1 SYNOPSIS

  use Range::ArrayIter qw(range_arrayiter);

  my $iter = range_arrayiter(1, 10);
  for (@$iter) { ... } # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

You can add step:

 my $iter = range_arrayiter(1, 10, 2); # 1, 3, 5, 7, 9

You can use alphanumeric strings too since C<++> has some extra builtin magic
(see L<perlop>):

 $iter = range_arrayiter("zx", "aab"); # zx, zy, zz, aaa, aab

Infinite list:

 $iter = range_arrayiter(1, Inf); # 1, 2, 3, ...

=head1 DESCRIPTION

B<PROOF OF CONCEPT.>

This module offers a tied-array-based iterator that you can use using for()
loop. It's most probably useful as a proof of concept only.

=for Pod::Coverage .+

=head1 FUNCTIONS

=head2 range_arrayiter($start, $end) => arrayref

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Range-ArrayIter>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-Range-ArrayIter>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Range-ArrayIter>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 SEE ALSO

L<Range::Iter>

L<Range::Iterator>

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2019 by perlancar@cpan.org.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut