File Coverage

blib/lib/Data/PrioQ/SkewBinomial.pm
Criterion Covered Total %
statement 97 111 87.3
branch 33 40 82.5
condition 9 9 100.0
subroutine 26 29 89.6
pod 6 6 100.0
total 171 195 87.6


line stmt bran cond sub pod time code
1             package Data::PrioQ::SkewBinomial;
2              
3 2     2   57192 use warnings; no warnings qw(recursion);
  2     2   6  
  2         66  
  2         10  
  2         4  
  2         63  
4 2     2   9 use strict;
  2         8  
  2         103  
5              
6             use constant {
7 2         416 ELEM => 0,
8             OTHERS => 1,
9             CHILDREN => 2,
10             RANK => 3,
11              
12             KEY => 0,
13             VALUE => 1,
14             HEAP => 2,
15              
16             HEAD => 0,
17             TAIL => 1,
18              
19             NIL => [],
20 2     2   10 };
  2         18  
21              
22             BEGIN {
23 2     2   4 *VERSION = \'0.03';
24              
25 2 50       12 unless (defined &_DEBUG) {
26 2         135 *_DEBUG = sub () { 0 };
27             }
28             }
29              
30             sub _confess {
31 0     0   0 require Carp;
32             {
33 2     2   12 no warnings 'redefine';
  2         4  
  2         4770  
  0         0  
34 0         0 *_confess = \&Carp::confess;
35             }
36 0         0 goto &Carp::confess;
37             }
38              
39             sub _assert {
40 0     0   0 my ($cond, $name) = @_;
41 0 0       0 unless ($cond) {
42 0         0 @_ = "assertion failed: $name";
43 0         0 goto &_confess;
44             }
45             }
46              
47             sub _length {
48 0     0   0 my ($xs) = @_;
49 0         0 my $n = 0;
50 0         0 while (@$xs) {
51 0         0 $xs = $xs->[TAIL];
52 0         0 ++$n;
53             }
54             $n
55 0         0 }
56              
57             sub _strip_rank {
58 53630     53630   62141 my ($t) = @_;
59 53630         224330 [@$t[ELEM, OTHERS, CHILDREN]]
60             }
61              
62             sub _link {
63 53630     53630   62518 my ($t1, $t2) = @_;
64 53630         48472 _assert $t1->[RANK] == $t2->[RANK], "trees have equal rank" if _DEBUG;
65              
66 53630 100       151749 $t1->[ELEM][KEY] <= $t2->[ELEM][KEY]
67             ? [$t1->[ELEM], $t1->[OTHERS], [_strip_rank($t2), $t1->[CHILDREN]], $t1->[RANK] + 1]
68             : [$t2->[ELEM], $t2->[OTHERS], [_strip_rank($t1), $t2->[CHILDREN]], $t1->[RANK] + 1]
69             }
70              
71             sub _skew_link {
72 3338     3338   4198 my ($x, $t1, $t2) = @_;
73 3338         4790 my $y = _link $t1, $t2;
74 3338         3841 _assert _length($y->[OTHERS]) + 1 <= $y->[RANK], "sufficient space in linked tree" if _DEBUG;
75 3338 100       18463 $x->[KEY] <= $y->[ELEM][KEY]
76             ? [$x, [$y->[ELEM], $y->[OTHERS]], $y->[CHILDREN], $y->[RANK]]
77             : [$y->[ELEM], [$x, $y->[OTHERS]], $y->[CHILDREN], $y->[RANK]]
78             }
79              
80             sub _insert {
81 9137     9137   11434 my ($ts, $x) = @_;
82 9137 100 100     17589 @$ts && @{$ts->[TAIL]} && $ts->[HEAD][RANK] == $ts->[TAIL][HEAD][RANK]
83             ? [_skew_link($x, $ts->[HEAD], $ts->[TAIL][HEAD]), $ts->[TAIL][TAIL]]
84             : [[$x, NIL, NIL, 0], $ts]
85             }
86              
87             sub _ins_tree {
88 26808     26808   29285 my ($t, $ts) = @_;
89 26808   100     114388 while (@$ts && $t->[RANK] >= $ts->[HEAD][RANK]) {
90 26150         24543 _assert !@{$ts->[TAIL]} || $ts->[HEAD][RANK] < $ts->[TAIL][HEAD][RANK], "tree ranks are strictly increasing" if _DEBUG;
91 26150         42892 $t = _link $t, $ts->[HEAD];
92 26150         126925 $ts = $ts->[TAIL];
93             }
94 26808         84260 [$t, $ts]
95             }
96              
97             sub _merge_trees {
98 68788     68788   74121 my ($ts1, $ts2) = @_;
99 68788 100       136525 @$ts1 or return $ts2;
100 62379 100       137790 @$ts2 or return $ts1;
101 49818         55581 my $t1 = $ts1->[HEAD];
102 49818         50574 my $t2 = $ts2->[HEAD];
103 49818         59868 my $cmp = $t1->[RANK] <=> $t2->[RANK];
104 49818 100       116467 $cmp < 0 ? [$t1, _merge_trees($ts1->[TAIL], $ts2)] :
    100          
105             $cmp > 0 ? [$t2, _merge_trees($ts1, $ts2->[TAIL])] :
106             _ins_tree _link($t1, $t2), _merge_trees($ts1->[TAIL], $ts2->[TAIL])
107             }
108              
109             sub _normalize {
110 37940     37940   37453 my ($ts) = @_;
111 37940 100       69809 if (@$ts) {
112 28214         48140 my $hd = $ts->[HEAD];
113 28214         27918 my $tl = $ts->[TAIL];
114 28214 100 100     128466 @$tl && $hd->[RANK] == $tl->[HEAD][RANK] and return _ins_tree $hd, $tl;
115             }
116             $ts
117 35274         62806 }
118              
119             sub _merge {
120 18970     18970   20396 my ($ts1, $ts2) = @_;
121 18970         25734 _merge_trees _normalize($ts1), _normalize($ts2)
122             }
123              
124             sub _split {
125 40725     40725   46747 my ($ts) = @_;
126 40725         44340 my $tl = $ts->[TAIL];
127 40725 100       74584 @$tl or return $ts->[HEAD], $tl;
128 31240         32124 my $t1 = $ts->[HEAD];
129 31240         41320 my ($t2, $ts2) = _split($tl);
130 31240 100       101146 $t1->[ELEM][KEY] <= $t2->[ELEM][KEY]
131             ? ($ts->[HEAD], $tl)
132             : ($t2, [$t1, $ts2])
133             }
134              
135             sub _rev_enrank {
136 9485     9485   10966 my ($r, $xs) = @_;
137 9485         9386 my $ys = NIL;
138 9485         17671 while (@$xs) {
139 57040         57303 --$r;
140 57040         44505 _assert $r >= 0, "rank $r >= 0" if _DEBUG;
141 57040         50457 $ys = [[@{$xs->[HEAD]}, $r], $ys];
  57040         149156  
142 57040         129606 $xs = $xs->[TAIL];
143             }
144             $ys
145 9485         19195 }
146              
147             sub _shift_min {
148 9485     9485   9765 my ($pq) = @_;
149 9485         14049 my ($t, $ts) = _split $pq;
150 9485         12644 my $xs = $t->[OTHERS];
151 9485         8052 _assert _length($xs) <= $t->[RANK], "not too many extra nodes in min tree" if _DEBUG;
152 9485         17050 my $ys = _merge _rev_enrank($t->[RANK], $t->[CHILDREN]), $ts;
153 9485         61043 while (@$xs) {
154 6762         11984 $ys = _insert $ys, $xs->[HEAD];
155 6762         18909 $xs = $xs->[TAIL];
156             }
157 9485         26038 $ys, $t->[ELEM]
158             }
159              
160             sub _bless {
161 14236     14236   17193 my ($self, $x) = @_;
162 14236         51703 bless $x, ref $self
163             }
164              
165             {
166             bless \my @e, __PACKAGE__;
167             sub empty {
168             \@e
169 26     26 1 69853 }
170             }
171              
172             sub is_empty {
173 9535     9535 1 187488 my $self = shift;
174 9535         19993 !@$self
175             }
176              
177             sub _singleton {
178 2376     2376   2682 my ($self, $k, $v) = @_;
179 2376         5465 $self->_bless([$k, $v, NIL])
180             }
181              
182             sub insert {
183 2376     2376 1 7866 my ($self, $k, $v) = @_;
184 2376         3671 $self->merge($self->_singleton($k, $v))
185             }
186              
187             sub merge {
188 2382     2382 1 21702 my ($self, $other) = @_;
189 2382 100       4441 @$self or return $other;
190 2375 50       4205 @$other or return $self;
191 2375 100       4762 my ($min, $max) = $self->[KEY] <= $other->[KEY] ? ($self, $other) : ($other, $self);
192 2375         4655 $self->_bless([@$min[KEY, VALUE], _insert $min->[HEAP], $max])
193             }
194              
195             sub peek_min {
196 1     1 1 3 my ($self) = @_;
197 1 50       10 @$self
198             ? ($self->[KEY], $self->[VALUE])
199             : ()
200             }
201              
202             sub _retfst {
203 9504 50   9504   42752 wantarray ? @_ : $_[0]
204             }
205              
206             sub shift_min {
207 9504     9504 1 30316 my ($self) = @_;
208 9504 50       16936 @$self or return _retfst $self, undef, undef;
209 9504 100       9461 @{$self->[HEAP]} or return _retfst ref($self)->empty, @$self[KEY, VALUE];
  9504         20135  
210 9485         17626 my ($h, $other) = _shift_min $self->[HEAP];
211 9485         21603 _retfst $self->_bless([@$other[KEY, VALUE], _merge $h, $other->[HEAP]]), @$self[KEY, VALUE]
212             }
213              
214             1
215             __END__