File Coverage

blib/lib/List/Insertion.pm
Criterion Covered Total %
statement 135 207 65.2
branch 20 64 31.2
condition 17 23 73.9
subroutine 25 26 96.1
pod 1 1 100.0
total 198 321 61.6


line stmt bran cond sub pod time code
1             package List::Insertion;
2              
3              
4 1     1   72556 use strict;
  1         2  
  1         29  
5 1     1   6 use warnings;
  1         1  
  1         23  
6              
7 1     1   567 use Template::Plex;
  1         20472  
  1         25  
8 1     1   499 use Data::Combination;
  1         711  
  1         58  
9 1     1   7 use Exporter;# qw;
  1         2  
  1         99  
10              
11              
12             our $VERSION = 'v0.1.2';
13              
14             sub make_search;
15              
16             sub import {
17              
18 8     8   569 shift;
19 8         21 my @import=@_;
20              
21             # Generate subs based on import options
22 8         23 my ($package)=caller;
23              
24             # Import make search if requested
25             #
26 8 100 100     64 if(@import==1 and grep /make_search/, @import){
27 1     1   7 no strict 'refs';
  1         2  
  1         69  
28 1         2 *{$package."::make_search"}=\&make_search;
  1         5  
29 1         24 return;
30             }
31            
32             # Otherwise assume we have a list of specifications
33 7         11 my @spec;
34 7         24 push @spec, (Data::Combination::combinations $_)->@* for @import;
35            
36 1     1   7 no strict 'refs';
  1         1  
  1         664  
37 7         595 for my $spec(@spec){
38 13   100     44 $spec->{prefix}//="search";
39 13   50     27 $spec->{type}//="string";
40 13   100     28 $spec->{duplicate}//="left";
41              
42 13         27 my ($sub,$code)=make_search $spec;
43 13 50       39 *{$package."::".$spec->{name}}=$sub if $sub;
  13         2513  
44             #say STDERR $code;
45             }
46             }
47              
48              
49              
50             my $template_base=
51             '
52             my \$middle;
53             my \$lower;
54             my \$upper;
55              
56             sub {
57             my (\$key, \$array)=\@_;
58             \$lower = 0;
59             \$upper = \@\$array;
60             return 0 unless \$upper;
61              
62             use integer;
63             # TODO: Run in eval for accessor fall back
64             #
65             # local \$_;
66             while(\$lower<\$upper){
67             \$middle=(\$upper+\$lower)>>1;
68             (\$key $condition->{$fields{type}}{$fields{duplicate}} \$array->[\$middle]$accessor)
69             $update->{$fields{duplicate}}
70             }
71             \$lower;
72             }
73             ';
74              
75             my %condition=(
76             string=>{
77             left=>'le',
78             right=>'ge',
79             },
80             numeric=>{
81             left=>'<=',
82             right=>'>='
83             },
84              
85             );
86              
87              
88             my %update=(
89             left=>
90             '
91             ? ($upper=$middle)
92             : ($lower=$middle+1)
93             ',
94              
95             right=>
96              
97             '
98             ? ($lower=$middle+1)
99             : ($upper=$middle)
100             '
101             );
102            
103              
104              
105             # Make a binary search optimised for types and avoid sub routine callbacks
106             #
107             sub make_search {
108 16     16 1 674 my ($options)=@_;
109              
110             # Ensure at least a default value for the required fields
111             #
112 16   50     32 $options->{duplicate}//="left";
113 16   50     30 $options->{type}//="string";
114 16   100     53 $options->{accessor}//="";
115 16   100     37 $options->{prefix}//="search";
116              
117             # Attempt to normalise values
118             #
119 16         30 $options->{duplicate}=~s/lesser/left/;
120 16         21 $options->{duplicate}=~s/greater/right/;
121              
122 16         38 $options->{type}=~s/pv/string/i;
123 16         32 $options->{type}=~s/nv/numeric/i;
124 16         28 $options->{type}=~s/int/numeric/i;
125              
126 16   33     88 $options->{name}//="$options->{prefix}_$options->{type}_$options->{duplicate}";
127              
128              
129             #Check fields values are supported
130              
131            
132             die "Unsupported value for duplicate field: $options->{duplicate }. Must be left or right"
133 16 50       77 unless $options->{duplicate }=~/^(left|right)$/;
134             die "Unsupported value for type field: $options->{type}. Must be string, pv, nv or int"
135 16 50       57 unless $options->{type}=~/^(string|numeric)$/;
136             die "Unsupported value for type field: $options->{accessor}. Must be post dereference/method call ->..."
137 16 50 66     52 unless $options->{accessor} eq "" or $options->{accessor}=~/^->/;
138              
139 16         106 my $template=Template::Plex->load( \$template_base, {condition=>\%condition, update=>\%update, accessor=>$options->{accessor}}, inject=>['use feature "signatures";']);
140 16         27927 my $code_str=$template->render({duplicate =>$options->{duplicate}, type=>$options->{type}});
141              
142             #use feature "say";
143             #use Error::Show;
144 1 0   1   644 my $sub=eval($code_str);
  1 0   1   38  
  1 0   1   5  
  1 0   1   7  
  1 0   1   3  
  1 0   1   4  
  1 0   1   7  
  1 0   1   3  
  1 0   1   4  
  1 0   1   8  
  1 0   1   3  
  1 0   1   4  
  1 0   1   8  
  1 0   1   2  
  1 50   1   5  
  1 100   1   8  
  1 0   0   2  
  1 0       5  
  1 50       7  
  1 100       19  
  1 0       8  
  1 0       7  
  1 50       5  
  1 100       5  
  1 50       8  
  1 100       2  
  1         6  
  1         7  
  1         3  
  1         5  
  1         7  
  1         3  
  1         8  
  1         8  
  1         2  
  1         5  
  1         8  
  1         2  
  1         10  
  1         10  
  1         2  
  1         6  
  1         8  
  1         2  
  1         4  
  1         8  
  1         3  
  1         5  
  16         3317  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         329  
  1         2  
  1         5  
  1         3  
  1         4  
  2         4  
  2         9  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  3         666  
  3         6  
  3         6  
  3         9  
  3         19  
  9         19  
  9         27  
  3         9  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2248  
  1         4  
  1         2  
  1         4  
  1         5  
  2         6  
  2         13  
  1         2  
  3         975  
  3         5  
  3         6  
  3         8  
  3         7  
  9         13  
  9         24  
  3         10  
145             #say STDERR Error::Show::context error=>$@, program=>$code_str if($@ or !$sub);
146             #say STDERR $code_str;
147 16 100       90 wantarray?($sub,$code_str):$sub;
148             }
149              
150             1;