File Coverage

blib/lib/Tie/Quicksort/Lazy.pm
Criterion Covered Total %
statement 67 72 93.0
branch 20 22 90.9
condition 1 3 33.3
subroutine 11 12 91.6
pod n/a
total 99 109 90.8


line stmt bran cond sub pod time code
1             package Tie::Quicksort::Lazy;
2             @Tie::Quicksort::Lazy::Stable::ISA = qw/ Tie::Quicksort::Lazy /;
3              
4 1     1   9918 use Carp;
  1         5  
  1         73  
5              
6 1     1   20 use 5.006001;
  1         3  
  1         34  
7 1     1   6 use strict;
  1         5  
  1         42  
8 1     1   6 use warnings;
  1         2  
  1         214  
9              
10             our $VERSION = '0.04';
11             sub DEBUG() { 0 };
12              
13             # object field names:
14             BEGIN {
15 1     1   3 my $i = 0;
16 1         2 for (qw/comparator size ready parts/){ # a coderef, then an arrayref, then an arrayref of arrayrefs.
17 4         1072 eval "sub $_ () {".$i++.'}'
18             }
19             }
20              
21             our $trivial = 2 ; # if you want to call sort you have to ask for it
22              
23             sub import {
24 1     1   7 shift; # lose package name
25 1         2 my %args = @_;
26 1   33     26 $trivial = $args{TRIVIAL} || $trivial;
27             };
28              
29             sub TIEARRAY{
30 2     2   592 my $obj = bless [];
31 2         4 shift; # lose package name
32 2 100       6 if ( ( ref $_[0] ) eq 'CODE' ) {
33 1         3 $obj->[comparator] = shift
34             }else{
35             $obj->[comparator] = sub {
36 28     28   26 DEBUG and ((defined $_[0] and defined $_[1] ) or Carp::confess "undefined arg to comparator");
37 1         14 $_[0] cmp $_[1] };
  28         72  
38             };
39              
40 2         5 $obj->[size] = @_;
41 2         3 $obj->[ready] = [];
42 2         9 $obj->[parts] = [ [ @_ ] ]; # the stack of unsorted partitions
43              
44 2         7 return $obj;
45             };
46              
47              
48             sub _sort {
49 21     21   29 my $obj = shift;
50 21         31 my $comp_func = $obj->[comparator];
51 21         28 for(;;){
52 33         33 my $arr = pop @{$obj->[parts]};
  33         98  
53 33         40 DEBUG and warn "arr is [ @$arr ]";
54              
55 33 100       97 if (@$arr == 1 ) {
    100          
    50          
56 18         29 $obj->[ready] = $arr ;
57             return
58 18         32 } elsif (@$arr == 2 ) {
59 3 100       45 $obj->[ready] = ( $comp_func->(@$arr) > 0 ? [@$arr[1,0]] : $arr ) ;
60             return
61 3         13 } elsif (@$arr <= $trivial ) {
62 0         0 $obj->[ready] = [ sort { $comp_func->($a,$b) } @$arr ];
  0         0  
63             return
64 0         0 };
65 12         20 my (@HighSide, @LowSide) = ();
66              
67             # by choosing a random pivot and treating equality differently
68             # when examining the before and after parts of the partition,
69             # we get stability without scrambling and without any
70             # degenerate cases, even contrived ones. (choosing the midpoint
71             # gives n*log(n) performance for sorted input, but it would be
72             # possible to contrive a quadratic case)
73            
74 12         84 my $pivot_index = int rand @$arr;
75            
76 12         18 my $pivot = $arr->[$pivot_index];
77            
78             # BEFORE THE PIVOT ELT:
79 12         35 for ( splice @$arr, 0, $pivot_index ) {
80 31 100       61 if ($comp_func->($pivot, $_) < 0 ){
81             # we are looking at an elt that belongs after the pivot
82 13         44 push @HighSide, $_
83             }else{
84 18         60 push @LowSide, $_
85             };
86             };
87            
88 12         117 shift @$arr; # shift off the pivot elt
89            
90             # AFTER THE PIVOT ELT:
91 12         24 for ( @$arr ) {
92 24 100       51 if ($comp_func->($pivot, $_) > 0 ){
93             # we are looking at an elt that belongs before the pivot
94 8         25 push @LowSide, $_
95             }else{
96 16         68 push @HighSide, $_
97             };
98             };
99            
100 12 100       33 @HighSide and push @{$obj->[parts]}, \@HighSide; # defer the high side
  10         20  
101 12         16 push @{$obj->[parts]}, [$pivot]; # this pivot,
  12         31  
102 12 100       41 @LowSide and push @{$obj->[parts]}, \@LowSide; # do the low side, if any, next
  9         28  
103             } # for (;;)
104              
105             }
106              
107              
108             sub FETCHSIZE {
109 26     26   26966 $_[0]->[size]
110             }
111              
112             sub SHIFT {
113 24     24   104 my $obj = shift;
114 24 50       68 $obj->[size] or return undef;
115 24         29 my $rarr = $obj->[ready];
116            
117 24 100       59 unless (@$rarr){
118 21         55 $obj->_sort;
119 21         29 $rarr = $obj->[ready];
120             };
121            
122 24         36 $obj->[size]-- ;
123 24         94 shift @$rarr;
124             }
125              
126             *STORE = *PUSH = *UNSHIFT = *FETCH =
127             *STORESIZE = *POP = *EXISTS = *DELETE =
128             *CLEAR = sub {
129 0     0     require Carp;
130 0           Carp::croak ('"SHIFT" and "FETCHSIZE" are the only methods defined for a '.
131             __PACKAGE__ . " array");
132             };
133              
134             1;
135             __END__