File Coverage

lib/Set/CartesianProduct/Lazy.pm
Criterion Covered Total %
statement 61 61 100.0
branch 6 10 60.0
condition n/a
subroutine 16 16 100.0
pod 4 4 100.0
total 87 91 95.6


line stmt bran cond sub pod time code
1 1     1   69296 use strict;
  1         2  
  1         28  
2 1     1   5 use warnings;
  1         2  
  1         60  
3             package Set::CartesianProduct::Lazy;
4             $Set::CartesianProduct::Lazy::VERSION = '0.004';
5             {
6             $Set::CartesianProduct::Lazy::DIST = 'Set-CartesianProduct-Lazy';
7             }
8              
9             # ABSTRACT: lazily calculate the tuples of a cartesian-product
10              
11 1     1   5 use List::Util qw( reduce );
  1         2  
  1         102  
12 1     1   7 use Scalar::Util qw( reftype );
  1         1  
  1         54  
13 1     1   576 use Data::Dumper;
  1         6849  
  1         71  
14 1     1   8 use Carp;
  1         3  
  1         522  
15              
16             sub new {
17 5     5 1 2543 my $class = shift;
18 5         12 my %opts = map { %$_ } grep { reftype $_ eq 'HASH' } @_;
  1         4  
  13         41  
19 5         10 my @sets = grep { reftype $_ eq 'ARRAY' } @_;
  13         29  
20              
21 5         12 my $getsub = __make_getsub(\%opts, \@sets);
22              
23 5         54 return bless { %opts, sets => \@sets, getsub => $getsub }, $class;
24             }
25              
26             sub __make_getsub {
27 5     5   8 my ($opts, $sets_ref) = @_;
28              
29             # TODO: eval code to produce the sub so the code isn't duplicated
30              
31 5 100       16 if ($opts->{less_lazy}) {
32              
33             # pre-calculate some things, so we don't have to every time.
34 1         2 my @sets = @$sets_ref;
35             my @info = map {
36 1     3   3 [ $_, (scalar @{$sets[$_]}), reduce { $a * @$b } 1, @sets[$_ + 1 .. $#sets] ];
  3         5  
  3         18  
  3         9  
37             } 0 .. $#sets;
38              
39             return sub {
40 2     2   3 my ($n) = @_;
41              
42             my @tuple = map {
43 2         5 my ($set_num, $set_size, $factor) = @$_;
  6         10  
44 6         15 $sets[ $set_num ][ int( $n / $factor ) % $set_size ];
45             } @info;
46              
47 2 50       10 return wantarray ? @tuple : \@tuple;
48 1         7 };
49             }
50              
51             return sub {
52 9     9   15 my ($n) = @_;
53              
54 9         20 my @tuple;
55              
56 9         18 my @sets = @$sets_ref;
57              
58 9         19 for my $set_num (0 .. $#sets) {
59 20         21 my $set_size = @{ $sets[$set_num] };
  20         28  
60 20         89 my $factor = reduce { $a * @$b } 1, @sets[$set_num + 1 .. $#sets];
  13         23  
61 20         55 my $idx = int( $n / $factor ) % $set_size;
62              
63 20         45 push @tuple, $sets[$set_num][$idx];
64             }
65              
66 9 50       37 return wantarray ? @tuple : \@tuple;
67 4         25 };
68             }
69              
70              
71             sub get {
72 11     11 1 1600 my $self = shift;
73 11 50       23 croak "no value passed to get method\n" unless defined $_[0];
74 11         22 $self->{getsub}->(@_);
75             }
76              
77              
78             #sub get_faster { my $self = shift; $self->{getsub}->(@_); }
79              
80             {
81 1     1   8 no warnings 'once';
  1         2  
  1         149  
82 25 50   25 1 55 sub count { return reduce { $a * @$b } 1, @{ shift->{sets} || [] } }
  10     10   42  
  10         54  
83             }
84              
85 3     3 1 1552 sub last_idx { return shift->count - 1 }
86              
87              
88             1 && q{a set in time saves nine};
89              
90             __END__