use v6-alpha;

##########################
# OO solution by eric256 #
##########################

my @loops = ([1..3], ['a'..'e'], ['foo', 'bar']);

class MultiCounter {
      has @.positions is rw;
      has @.lengths   is rw;
      submethod BUILD() { @.positions = (0) xx (@.lengths.end + 1); }
      method inc () returns Bool {
        @.positions[-1]++;
        for reverse (0..@.lengths.end - 1) -> $i {
         if (@.positions[$i + 1] > @.lengths[$i + 1]) {
            @.positions[$i]++;
            @.positions[$i + 1] = 0;
         }
        }
        return (@.positions[0] > @.lengths[0]) ?? 0 !! 1;             
      }                
}

class NestedLoops {
      has @.loops is rw;
      has MultiCounter $.counter is r;
      submethod BUILD($self:) {
          $self.reset;
      }
      method reset () {
          $.counter = MultiCounter.new( :lengths( @.loops.map:{.end } ) );
      }
      multi method iter () returns Bool { $.counter.inc;  }
      multi method iter ($self: Code $code) {
             while ($self.iter) { $code($self.data) };
             $self.reset;
      }
      method data () {
          return map -> $i { @.loops[$i][ $.counter.positions[$i] ] }, 0 .. @.loops.end;
      };
}

my $counter = NestedLoops.new( :loops(@loops) );

$counter.iter( sub { say "CODE BLOCK " ~ @_ } );
while ($counter.iter) { say "WHILE LOOP " ~ $counter.data.join(" "); }

