``````use strict;
package Algorithm::GenerateSequence;
use vars qw( \$VERSION );
\$VERSION = '0.02';

Algorithm::GenerateSequence - a sequence generator

my \$gen = Algorithm::GenerateSequence->new(
[qw( one two three )], [qw( hey bee )],
);
print join(' ', \$gen->next), "\n"; # one hey
print join(' ', \$gen->next), "\n"; # one bee
print join(' ', \$gen->next), "\n"; # two hey
print join(' ', \$gen->next), "\n"; # two bee
...

Algorithm::GenerateSequence provides an iterator interface to a
sequence you define in terms of the symbols to use in each position.

You may use a different amount of symbols in each position and the
module will iterate over them correctly.  This might be useful in
identifying all the cards in a deck:

my \$deck = Algorithm::GenerateSequence->new(
[qw( Heart Diamond Spade Club )],
[qw( A 2 3 4 5 6 7 8 9 10 J Q K )],
);

Or for a range of addresses to scan:

my \$scan = Algorithm::GenerateSequence->new(
[192], [168], [0..254], [1]
);

@values contains arrays of symbols which will be used to form the
sequence

=cut

sub new {
my \$class = shift;

my @values = @_;
my @counters = (0) x @values;
my (\$started, \$ended);

bless sub {
return if \$ended;

if (\$started++) {
my \$max = \$#counters;

do {
my \$new = ++\$counters[ \$max ];
# check for overflow
goto DONE if \$new % @{ \$values[ \$max ] };
\$counters[ \$max ] = 0;
} while --\$max >= 0;
DONE:
if (\$max < 0) {
\$ended = 1;
return;
}
}

my \$i = 0;
return map { \$values[ \$i++ ][ \$_ ] } @counters;
}, ref \$class || \$class;
}

returns a list containing the next value in the sequence, or false if
at the end of the sequence

=cut

sub next { \$_[0]->() }

return the remainder of the sequence as a list of array references

=cut

sub as_list {
my \$self = shift;

my @results;
while (my @next = \$self->()) {
push @results, \@next;
}
return @results;
}

1;
__END__

None currently known.  If you find any please make use of
L<http://rt.cpan.org> by mailing your report to
bug-Algorithm-GenerateSequence@rt.cpan.org, or contact me directly.