File Coverage

blib/lib/SkewHeap/PP.pm
Criterion Covered Total %
statement 38 79 48.1
branch 8 22 36.3
condition 5 7 71.4
subroutine 14 25 56.0
pod 18 22 81.8
total 83 155 53.5


line stmt bran cond sub pod time code
1             package SkewHeap::PP;
2             # ABSTRACT: a fast and flexible heap structure
3             $SkewHeap::PP::VERSION = '0.02';
4              
5             #-------------------------------------------------------------------------------
6             # Boilerplate
7             #-------------------------------------------------------------------------------
8 1     1   232430 use strict;
  1         7  
  1         32  
9 1     1   5 use warnings;
  1         3  
  1         51  
10              
11             #-------------------------------------------------------------------------------
12             # Node array index constants
13             #-------------------------------------------------------------------------------
14             my $KEY = 0;
15             my $LEFT = 1;
16             my $RIGHT = 2;
17              
18             #-------------------------------------------------------------------------------
19             # Skew heap array index constants
20             #-------------------------------------------------------------------------------
21             my $CMP = 0;
22             my $SIZE = 1;
23             my $ROOT = 2;
24              
25             #-------------------------------------------------------------------------------
26             # Exports
27             #-------------------------------------------------------------------------------
28 1     1   473 use parent 'Exporter';
  1         294  
  1         6  
29             our @EXPORT = qw(
30             skew
31             skew_count
32             skew_is_empty
33             skew_peek
34             skew_put
35             skew_take
36             skew_merge
37             skew_merge_safe
38             skew_explain
39             );
40              
41             #-------------------------------------------------------------------------------
42             # Common interface
43             #-------------------------------------------------------------------------------
44 2     2 1 6209 sub skew (&) { [ $_[0], 0, undef ] }
45 6     6 1 810 sub skew_count ($) { $_[0][$SIZE] }
46 6     6 1 818 sub skew_is_empty ($) { $_[0][$SIZE] == 0 }
47              
48             sub clone_node {
49 0     0 0 0 my $node = shift;
50 0 0       0 return unless defined $node;
51              
52             return [
53 0         0 $node->[$KEY],
54             clone_node($node->[$LEFT]),
55             clone_node($node->[$RIGHT]),
56             ];
57             }
58              
59             sub merge_nodes_safe {
60 0     0 0 0 my ($cmp, $a, $b) = @_;
61              
62 0 0       0 return clone_node($a) unless defined $b;
63 0 0       0 return clone_node($b) unless defined $a;
64              
65 0 0       0 ($a, $b) = ($b, $a)
66             if $cmp->($a->[$KEY], $b->[$KEY]) > 0;
67              
68             return [
69 0         0 $a->[$KEY],
70             merge_nodes_safe($cmp, $b, $a->[$RIGHT]),
71             clone_node($a->[$LEFT]),
72             ];
73             }
74              
75             sub merge_nodes {
76 21741     21741 0 30254 my ($cmp, $a, $b) = @_;
77              
78 21741 100       33076 return $a unless defined $b;
79 18743 100       27578 return $b unless defined $a;
80              
81 18739 100       28202 ($a, $b) = ($b, $a)
82             if $cmp->($a->[$KEY], $b->[$KEY]) > 0;
83              
84 18739         67167 my $tmp = $a->[$RIGHT];
85 18739         22766 $a->[$RIGHT] = $a->[$LEFT];
86 18739         25805 $a->[$LEFT] = merge_nodes($cmp, $b, $tmp);
87              
88 18739         25362 return $a;
89             }
90              
91             sub skew_peek {
92 0     0 1 0 my $skew = shift;
93 0 0       0 return if skew_is_empty($skew);
94 0         0 return $skew->[$ROOT][$KEY];
95             }
96              
97             sub skew_take {
98 503     503 1 1923 my ($skew, $want) = @_;
99 503         565 my @taken;
100              
101 503   100     1834 while (($want || 1) > @taken && $skew->[$SIZE] > 0) {
      100        
102 1501         2215 push @taken, $skew->[$ROOT][$KEY];
103              
104 1501         2341 $skew->[$ROOT] = merge_nodes(
105             $skew->[$CMP],
106             $skew->[$ROOT][$LEFT],
107             $skew->[$ROOT][$RIGHT],
108             );
109              
110 1501         4677 --$skew->[$SIZE];
111             }
112              
113 503 100       1110 return defined($want) ? @taken : $taken[0];
114             }
115              
116             sub skew_put {
117 503     503 1 1253 my $skew = shift;
118              
119 503         714 for (@_) {
120 1501         2964 $skew->[$ROOT] = merge_nodes(
121             $skew->[$CMP],
122             $skew->[$ROOT],
123             [$_, undef, undef],
124             );
125              
126 1501         2182 ++$skew->[$SIZE];
127             }
128              
129 503         788 return $skew->[$SIZE];
130             }
131              
132             sub skew_merge {
133 0     0 1 0 my $skew = shift;
134              
135 0         0 for (@_) {
136 0         0 $skew->[$ROOT] = merge_nodes(
137             $skew->[$CMP],
138             $skew->[$ROOT],
139             $_->[$ROOT],
140             );
141              
142 0         0 $skew->[$SIZE] += $_->[$SIZE];
143 0         0 $_->[$ROOT] = undef;
144 0         0 $_->[$SIZE] = 0;
145             }
146              
147 0         0 return $skew;
148             }
149              
150             sub skew_merge_safe {
151 0     0 1 0 my $skew = [ $_[0][$CMP], 0, undef ];
152              
153 0         0 for (@_) {
154 0         0 $skew->[$ROOT] = merge_nodes_non_destructive(
155             $skew->[$CMP],
156             $skew->[$ROOT],
157             $_->[$ROOT],
158             );
159              
160 0         0 $skew->[$SIZE] += $_->[$SIZE];
161             }
162              
163 0         0 return $skew;
164             }
165              
166             sub node_explain {
167 0     0 0 0 my $node = shift;
168 0   0     0 my $indent_size = shift || 0;
169              
170 0         0 my $indent = ' ' x $indent_size;
171 0         0 print $indent.'- Node: '.$node->[$KEY]."\n";
172              
173 0 0       0 if ($node->[$LEFT]) {
174 0         0 node_explain($node->[$LEFT], $indent_size + 1);
175             }
176              
177 0 0       0 if ($node->[$RIGHT]) {
178 0         0 node_explain($node->[$RIGHT], $indent_size + 1);
179             }
180             }
181              
182             sub skew_explain {
183 0     0 1 0 my $skew = shift;
184 0         0 my $n = skew_count($skew);
185 0         0 print "SkewHeap\n";
186 0         0 node_explain($skew->[$ROOT], 1);
187             }
188              
189             #-------------------------------------------------------------------------------
190             # Object inteface
191             #-------------------------------------------------------------------------------
192 3     3 1 609 sub count { goto \&skew_count }
193 3     3 1 677 sub is_empty { goto \&skew_is_empty }
194 0     0 1 0 sub peek { goto \&skew_peek }
195 2     2 1 25 sub put { goto \&skew_put }
196 2     2 1 9 sub take { goto \&skew_take }
197 0     0 1 0 sub merge { goto \&skew_merge }
198 0     0 1 0 sub explain { goto \&skew_explain }
199              
200             sub new {
201 1     1 1 68891 my ($class, $cmp) = @_;
202 1         5 bless(skew(\&$cmp), $class);
203             }
204              
205             sub merge_safe {
206 0     0 1   my $self = shift;
207 0           my $new = skew_merge_safe($self->[$CMP], @_);
208 0           bless($new, ref($self));
209             }
210              
211             1;
212              
213             __END__