File Coverage

blib/lib/Heap/Simple/Perl.pm
Criterion Covered Total %
statement 188 188 100.0
branch 74 86 86.0
condition 19 33 57.5
subroutine 72 72 100.0
pod 0 25 0.0
total 353 404 87.3


line stmt bran cond sub pod time code
1             package Heap::Simple::Perl;
2 5     5   225552 use strict;
  5         14  
  5         193  
3 5     5   28 use Carp;
  5         11  
  5         339  
4              
5 5     5   37 use vars qw($VERSION $auto %used);
  5         10  
  5         430  
6             $VERSION = "0.12";
7             $auto = "Auto";
8             %used = ();
9              
10 5     5   8214 use AutoLoader qw(AUTOLOAD);
  5         10265  
  5         32  
11              
12 5     5   193 use constant DEBUG => 0;
  5         11  
  5         3692  
13              
14             sub _use {
15 22     22   41 my $name = shift();
16 22         86 $name =~ s|::|/|g;
17 22         30 print STDERR "require Heap/Simple/$name.pm\n" if DEBUG;
18 22         26860 return require "Heap/Simple/$name.pm";
19             }
20              
21             my %order = ("<" => "Number",
22             ">" => "NumberReverse",
23             "lt" => "String",
24             "gt" => "StringReverse",
25             );
26             sub _order {
27 2387     2387   4384 my ($heap, $order) = @_;
28             # Default order if nothing specified
29 2387 100 66     16485 $order = "<" unless defined($order) && $order ne "";
30 2387         3091 my $name;
31 2387 100       7182 if (ref($order) eq "CODE") {
32 977         2354 $heap->[0]{order} = $order;
33 977         1859 $name = "Less";
34             } else {
35 1410   66     5740 $name = $order{lc $order} || croak "Unknown order '$order'";
36             }
37 2385   66     7640 $used{$name} ||= _use($name);
38 2385         6743 return $name;
39             }
40              
41             sub _elements {
42 2385     2385   4717 my ($heap, $elements) = @_;
43 2385 100       7655 $elements = ["Scalar"] unless defined($elements);
44 2385 100       7570 $elements = [$elements] if ref($elements) eq "";
45 2385 50       7134 croak "option elements is not an array reference" unless
46             ref($elements) eq "ARRAY";
47 2385 50       6611 croak "option elements has no type defined at index 0" unless
48             defined($elements->[0]);
49 2385         7164 my $name = ucfirst(lc($elements->[0]));
50 2385 100       5567 $name = "Scalar" if $name eq "Key";
51 2385   66     7015 $used{$name} ||= _use($name);
52             # $name is passed for the case that Heap::Simple::$name uses inheritance
53 2384         17039 return "Heap::Simple::$name"->_elements($heap, $name, $elements);
54             }
55              
56             sub _max_count {
57 2389     2389   4274 my ($heap, $max_count) = @_;
58 2389 100       7632 return unless defined $max_count;
59 1001 100       3924 $max_count == int($max_count) ||
60             croak "max_count should be an integer";
61 1000 100       3180 croak "max_count should not be negative" if $max_count < 0;
62 999 50       3081 croak "max_count should not be zero" if $max_count == 0;
63 999 100       6616 return $max_count == 9**9**9 ? () : (Limit => $heap->[0]{max_count} = $max_count);
64             # my $name = "Limit";
65             # $used{$name} ||= _use($name);
66             # return "Heap::Simple::$name"->_max_count($heap, $name, $max_count);
67             }
68              
69             sub new {
70 2390 100   2390 0 8025801 croak "Odd number of elements in options" if @_ % 2 == 0;
71 2389         13415 my ($class, %options) = @_;
72             # note: the array starts at elements 1 to make the subscripting
73             # operations (much!) cleaner.
74             # So elements 0 is used for associated data
75 2389         14460 my $heap = bless [{}], $class;
76             # We temporarily bless $heap into $class so you can play OO games with it
77 2389         12074 my @max = $heap->_max_count(delete $options{max_count});
78 2387 100       9786 my @die = delete $options{can_die} ? "Die" : ();
79 2387 100       11692 $heap->[0]{can_die} = 1 if @die;
80 2387         9280 my @order = $heap->_order(delete $options{order});
81 2385         10007 my @elements = $heap->_elements(delete $options{elements});
82 2381         11104 my $gclass = join("::", $class, $auto, @max, @die, @order, @elements);
83             # Pure perl version is never dirty
84 2381 100       8616 $heap->[0]{dirty} = 1 if delete $options{dirty};
85 5     5   32 no strict "refs";
  5         11  
  5         14325  
86 361         12798 @{"${gclass}::ISA"} = ("Heap::Simple::$elements[0]",
  2381         24350  
87             "Heap::Simple::$order[0]",
88 2381 100       2999 $class) unless @{"${gclass}::ISA"};
89 2381         3995 print STDERR "Generated class $gclass\n" if DEBUG;
90             # Now rebless the result into its final generated class
91 2381         7740 bless $heap, $gclass;
92 2381 100       15296 $heap->[0]{infinity} = exists($options{infinity}) ?
93             delete $options{infinity} : $heap->_INF;
94 2381 100       7102 $heap->[0]{user_data} = delete $options{user_data} if
95             exists $options{user_data};
96 2381 100       5656 croak "Unknown option ", join(", ", map "'$_'", CORE::keys %options) if
97             %options;
98 2380         12351 return $heap;
99             }
100              
101             sub _ELEMENTS_PREPARE {
102 164     164   1380 return "";
103             }
104              
105             sub _ORDER_PREPARE {
106 730     730   5515 return "";
107             }
108              
109             sub _PREPARE {
110 672     672   2473 my $heap = shift;
111 672         4696 return join("", $heap->_ORDER_PREPARE, $heap->_ELEMENTS_PREPARE);
112             }
113              
114             sub _VALUE {
115 811     811   32777 return $_[1];
116             }
117              
118             sub _WRAPPER {
119 310     310   17821 return $_[2];
120             }
121              
122             sub _INF {
123 1072     1072   4154 return;
124             }
125              
126             sub _CAN_DIE {
127 2218 50   2218   33084 return shift->[0]{can_die} ? shift : @_ > 1 ? $_[1] : "";
    100          
128             }
129              
130             sub _CANT_DIE {
131 335 100   335   4627 return shift->[0]{can_die} ? "" : shift;
132             }
133              
134             sub _MAX_COUNT {
135 2028 50   2028   20871 return shift->[0]{max_count} ? shift : @_ > 1 ? $_[1] : "";
    100          
136             }
137              
138             sub _THE_MAX_COUNT {
139 1277   33 1277   23304 return shift->[0]{max_count} || croak "undefined max_count";
140             }
141              
142             sub _REAL_KEY {
143 367     367   1792 return shift->_KEY(@_);
144             }
145              
146             sub _REAL_ELEMENTS_PREPARE {
147 95     95   596 return shift->_ELEMENTS_PREPARE(@_);
148             }
149              
150             sub _REAL_PREPARE {
151 205     205   500 my $heap = shift;
152 205         1959 return join("", $heap->_ORDER_PREPARE, $heap->_REAL_ELEMENTS_PREPARE);
153             }
154              
155             # Returning "-" means it should not get used
156             # (should cause a syntax error on accidental use)
157             sub _QUICK_KEY {
158 20     20   560 return "-";
159             }
160              
161             sub _COMMA {
162 51     51   334 return ",";
163             }
164              
165             my %stringify =
166             ("\"" => "\\\"",
167             "\\" => "\\\\",
168             "\$" => "\\\$",
169             "\@" => "\\\@",
170             "\n" => "\\n",
171             "\r" => "\\r");
172              
173             # currently loses utf8 when the resulting string gets used
174             sub _stringify {
175 676 50   676   1483 defined(my $str = shift) || croak "undefined access";
176 676         1050 $str =~ s/([\"\\\n\r\$\@])/$stringify{$1}/g; # "
177 676         3641 return qq("$str");
178             }
179              
180             my ($balanced, $sequence);
181             # String with balanced parenthesis (but not balanced {}. We use that)
182             $balanced = qr{[^()\[\],]*(?:(?:\((??{$sequence})\)|\[(??{$sequence})\])[^()\[\],]*)*};
183             $sequence = qr{$balanced(?:,$balanced)*};
184              
185             sub _make {
186             # Use $_self so there is less chance of the eval using $heap and surviving
187 1955     1955   3348 my $_self = shift;
188 1955 50       7097 die "Cannot determine caller class from '$_self'" unless ref($_self);
189 1955         15635 my $subroutine = (caller(1))[3];
190 1955 50       13086 $subroutine =~ s/.*:://s || die "Cannot parse caller '$subroutine'";
191 1955         3846 my $package = ref($_self);
192              
193 1955         10484 my $string = "package $package;\n" . shift;
194             # Very simple macro expander, but ignore literal strings
195 1955         4395 my $f = "a";
196             # 1 while $string =~ s{(\b_[A-Z_]+)\(($sequence)\)}{$f=$1; $_self->$f($2 =~ /($balanced),?/g)}eg;
197             # Previous line ought to work but actually fails on perl 5.6.2 because
198             # the return value from s///e cannot be trusted
199 1955         181589 $f="",$string =~ s{(\b_[A-Z_]+)\(($sequence)\)}{$f=$1; $_self->$f($2 =~ /($balanced),?/g)}eg while $f;
  20853         37558  
  20853         1046286  
200 1955 100       12544 if ($string =~ /\bmy\s+\$(\w+)\s*=\s*shift;/g) {
201 1586         4167 my $var = $1;
202 1586 50       10122 $string =~ /\$$var\b/g || croak "$_self uses \$$var only once ($string)";
203 1586 100       9648 unless ($string =~ /\$$var\b/g) {
204             # Should also check for extra shifts really
205 165 50       686 croak "Candidate uses $1:\n$string" if $string =~ /(\$_\[[^\]]\])/;
206             # main::diag("Candidate: $string");
207 165         2293 $string =~ s/\bmy\s+\$$var\s*=\s*shift;(?:\s*\n)?(.*)\$$var\b/$1shift/s;
208             # main::diag("Now: $string");
209             }
210             }
211             # $string =~ s/(sub\s+\w+)\s*{.*\bCarp::croak\b\s*(\"[^\"]+\");.*}/$1 { Carp::croak $2 }/s; # "
212             # Important that these are last one since they can expand to something
213             # that contain the others
214 1955         9174 $string =~ s{\b_(LITERAL|STRING)\b}{
215 1426 50       8684 $1 eq "LITERAL" ?
    100          
216             defined $_self->[0]{index} ? $_self->[0]{index} : croak("undefined access") :
217             _stringify($_self->[0]{index})}eg;
218 1955         30626 $string
219             =~ s/^([^\S\n]*sub\s+(\w+)\s*\{)/#line 1 "${package}::$2"\n$1/mg;
220 1955         2756 print STDERR "Code:\n$string\n" if DEBUG;
221 1955         3885 my $err = $@;
222 1955     419   494637 eval $string;
  349     670   94369  
  313     94   3644  
  419     4   99251  
  278     4   3973  
  228     4   2314  
  278     4   2305  
  228     4   2235  
  228     4   2269  
  278     4   2254  
  278     4   3116  
  670     4   298634  
  670     4   6219  
  670     4   2294  
  670     4   3836  
  670     4   2905  
  670     4   5196  
  94     4   42176  
  94     4   2046  
  94     4   72842  
  4         1660  
223 1955 50       7000 die $@ if $@;
224 1955         64471 $@ = $err;
225             }
226              
227             sub count {
228 3942     3942 0 3133287 return $#{+shift};
  3942         20388  
229             }
230              
231             sub extract_all {
232 180     180 0 326565 my $heap = shift;
233 180         1017 return map $heap->extract_top, 2..@$heap;
234             }
235              
236             sub clear {
237 440     440 0 358074 $#{+shift} = 0;
  440         2451  
238             }
239              
240             sub absorb {
241 271     271 0 104621 my $heap = shift;
242 271         3437 $_->_absorb($heap) for @_;
243             }
244              
245             sub key_absorb{
246 183     183 0 60513 my $heap = shift;
247 183         2072 $_->_key_absorb($heap) for @_;
248             }
249              
250             sub wrapped {
251 186     186 0 129890 return;
252             }
253              
254             sub max_count {
255 312   100 312 0 47679 return shift->[0]{max_count} || 9**9**9;
256             }
257              
258             sub dirty {
259 180   66 180 0 108665 return shift->[0]{dirty} || (wantarray() ? () : !1);
260             }
261              
262             sub can_die {
263 1204   66 1204 0 170216 return shift->[0]{can_die} || (wantarray() ? () : !1);
264             }
265              
266             sub key_index {
267 160     160 0 146037 croak "Heap elements are not of type 'Array'";
268             }
269              
270             sub key_name {
271 160     160 0 123333 croak "Heap elements are not of type 'Hash'";
272             }
273              
274             sub key_method {
275 100     100 0 77367 croak "Heap elements are not of type 'Method' or 'Object'";
276             }
277              
278             sub key_function {
279 140     140 0 140847 croak "Heap elements are not of type 'Function' or 'Any'";
280             }
281              
282             sub key_insert {
283 180     180 0 72164 croak "This heap type does not support key_insert";
284             }
285              
286             sub _key_insert {
287 210     210   101202 croak "This heap type does not support _key_insert";
288             }
289              
290             sub implementation() {
291 365     365 0 4716 return __PACKAGE__;
292             }
293              
294             1;
295              
296             __END__