File Coverage

lib/Sort/MergeSort.pm
Criterion Covered Total %
statement 49 53 92.4
branch 18 22 81.8
condition n/a
subroutine 6 7 85.7
pod 0 1 0.0
total 73 83 87.9


line stmt bran cond sub pod time code
1              
2             package Sort::MergeSort;
3              
4 1     1   506 use strict;
  1         2  
  1         155  
5 1     1   5 use warnings;
  1         2  
  1         29  
6 1     1   431 use Sort::MergeSort::Iterator;
  1         14  
  1         562  
7             require Exporter;
8             our @ISA = qw(Exporter);
9             our @EXPORT = qw(mergesort);
10              
11             our $VERSION = 0.31;
12              
13             our $max_array = 64;
14              
15             sub mergesort
16             {
17 33     33 0 127 my ($compare, @inputs) = @_;
18              
19             #printf "Number of inputs: %d\n", scalar(@inputs);
20              
21             #
22             # Since we'll be using splice, don't use really wide arrays
23             #
24              
25 33 100       72 if (@inputs > $max_array) {
26 5         6 my @new_array;
27 5         28 while (@inputs) {
28 21         74 push(@new_array, mergesort($compare, splice(@inputs, 0, $max_array)));
29             }
30 5         13 return mergesort($compare, @new_array);
31             }
32              
33 28 50       85 if (@inputs == 1) {
    50          
34 0         0 return $inputs[0];
35             } elsif (@inputs == 0) {
36 0     0   0 return Sort::MergeSort::Iterator->new(sub { undef });
  0         0  
37             }
38              
39 28         32 my @data;
40              
41 28         41 for my $i (@inputs) {
42 153         348 my $first = <$i>;
43 153 50       320 next unless defined $first;
44 153         372 push(@data, [ $first, $i ]);
45             }
46              
47             # Sort high to low so that the element we want can be
48             # pop()ed off the end. Cheaper than shift.
49              
50 28         76 @data = sort { $compare->($b->[0], $a->[0]) } @data;
  247         686  
51              
52             #print join(", ", map { $_->[0] } @data)."\n";
53              
54             return Sort::MergeSort::Iterator->new(sub {
55 44878 100   44878   83859 return undef unless @data;
56              
57 44850         57823 my $popped = pop(@data);
58              
59 44850         60316 my $retval = $popped->[0];
60 44850         52217 my $iter = $popped->[1];
61 44850         99596 my $new = $popped->[0] = <$iter>;
62 44850 100       103241 return $retval unless defined $new;
63              
64             # if ($compare->($new, $retval) < 0) {
65             # die "Unsorted inputs $new $retval";
66             # }
67              
68 44697 100       85962 unless(@data) {
69 145         194 @data = $popped;
70 145         298 return $retval;
71             }
72              
73 44552         49396 my $min = 0;
74 44552         55505 my $max = $#data;
75              
76 44552         87704 while ($max - $min >= 2) {
77 1     1   1634 use integer;
  1         10  
  1         4  
78 87747         98389 my $mid = ($min + $max) / 2; # rounds down
79 87747         180297 my $c = $compare->($data[$mid][0], $new);
80             #print "new=$new [ $min, $mid, $max ] = $c\n";
81 87747 100       285653 if ($c > 0) {
    50          
82 46683         98672 $min = $mid;
83             } elsif ($c < 0) {
84 41064         90922 $max = $mid;
85             } else {
86 0         0 $max = $min = $mid;
87             }
88             }
89 44552 100       104935 if ($compare->($data[$max][0], $new) > 0) {
    100          
90 7560         24763 splice(@data, $max+1, 0, $popped);
91             } elsif ($compare->($data[$min][0], $new) > 0) {
92 30025         171182 splice(@data, $max, 0, $popped);
93             } else {
94 6967         38837 splice(@data, $min, 0, $popped);
95             }
96              
97             #print join(", ", map { $_->[0] } @data)."\n";
98             #die unless is_sorted(reverse map { $_->[0] } @data);
99              
100 44552         102074 return $retval;
101 28         274 });
102             }
103              
104             #sub is_sorted
105             #{
106             # my $ok = 1;
107             # for my $i (1..$#_) {
108             # next if $_[$i] >= $_[$i-1];
109             # $ok = 0;
110             # }
111             # return $ok;
112             #}
113              
114             1;
115              
116             __END__