# -*- perl -*-
#
# $Id: MultiIterator.pm,v 1.2 1995/07/25 02:19:16 qjb Exp $
# $Source: /home/qjb/source/perl/modules/RCS/MultiIterator.pm,v $
# $Author: qjb $
#
# MultiIterator package.  Takes a list of bounds, and iterates from 0
# to the bound (with upper bound non-inclusive) on each variable.  See
# test function for sample usage.
# 

require 5.000;
use strict qw(refs subs);

package MultiIterator;
$package = "MultiIterator";

# Field names
$f_bounds = "bounds";
$f_values = "values";
$f_finished = "finished";

# Static Variables

# Routines

sub new
{
    shift;
    my $rep = +{$package => {} };

    if (@_ == 0)
    {
	die "$package: new $package(bound, bound, ...)";
    }

    $rep->{$package}{$f_bounds} = [@_];
    local(@values) = ();
    map { push(@values, 0) } @_;
    $rep->{$package}{$f_values} = [@values];

    bless $rep;

    $rep->finished();

    $rep;
}

sub finished
{
    my $rep = shift;
    local($bounds, $values) =
	($rep->{$package}{$f_bounds},
	 $rep->{$package}{$f_values}
	 );

    # We're done when the most significant value has reached its bound
    $rep->{$package}{$f_finished} = ($values->[0] >= $bounds->[0]);
}

sub step
{
    my $rep = shift;
    local($bounds, $values) =
	($rep->{$package}{$f_bounds},
	 $rep->{$package}{$f_values}
	 );

    if ($rep->finished())
    {
	undef;
    }
    else
    {
	local($val) = join('/', @$values);
	local($i);
	# Increase values from least significant value to most significant
	# value.  If one value hits its bound, reset to zero and try the next.
	# Do not reset most significant to value when it hits its bound since
	# this is the termination condition.
	for ($i = scalar(@$bounds) - 1; $i >= 0; $i--)
	{
	    $values->[$i]++;
	    if ($values->[$i] < $bounds->[$i])
	    {
		last;
	    }
	    elsif ($i > 0)
	    {
		$values->[$i] = 0;
	    }
	}
	$val;
    }
}

sub test
{
    shift;
    local($t) = new MultiIterator(@_);
    local($v);
    while (defined($v = $t->step()))
    {
	print $v, "\n";
    }
}

1;
