File Coverage

blib/lib/Sort/Key/Merger.pm
Criterion Covered Total %
statement 132 160 82.5
branch 25 52 48.0
condition 9 13 69.2
subroutine 25 39 64.1
pod 17 17 100.0
total 208 281 74.0


line stmt bran cond sub pod time code
1             package Sort::Key::Merger;
2              
3             our $VERSION = '0.10_02';
4              
5 3     3   101136 use strict;
  3         8  
  3         155  
6 3     3   17 use warnings;
  3         7  
  3         103  
7 3     3   31 use Carp;
  3         13  
  3         355  
8              
9 3     3   3699 use Sort::Key::Types;
  3         6173  
  3         516  
10             our @CARP_NOT = qw(Sort::Key::Types);
11              
12             # use Data::Dumper qw(Dumper);
13              
14             require Exporter;
15             our @ISA = qw(Exporter);
16             our @EXPORT_OK = qw(keymerger nkeymerger ikeymerger ukeymerger
17             rkeymerger rnkeymerger rikeymerger rukeymerger
18             filekeymerger nfilekeymerger ifilekeymerger ufilekeymerger
19             rfilekeymerger rnfilekeymerger rifilekeymerger rufilekeymerger);
20              
21             require XSLoader;
22             XSLoader::load('Sort::Key::Merger', $VERSION);
23              
24 3     3   24 use constant STR_SORT => 0;
  3         5  
  3         162  
25 3     3   15 use constant LOC_STR_SORT => 1;
  3         7  
  3         124  
26 3     3   16 use constant NUM_SORT => 2;
  3         7  
  3         128  
27 3     3   16 use constant INT_SORT => 3;
  3         9  
  3         131  
28 3     3   18 use constant UINT_SORT => 4;
  3         7  
  3         123  
29 3     3   36 use constant REV_SORT => 128;
  3         4  
  3         130  
30              
31              
32 3     3   15 use constant VALUE => 0;
  3         4  
  3         124  
33 3     3   14 use constant FILE => 1;
  3         5  
  3         139  
34 3     3   14 use constant SCRATCHPAD => 2;
  3         5  
  3         122  
35 3     3   29 use constant RS => 2;
  3         5  
  3         131  
36 3     3   24 use constant KEY0 => 3;
  3         6  
  3         180  
37              
38             my ($int_hints, $locale_hints);
39             BEGIN {
40 3     3   3522 use integer;
  3         30  
  3         17  
41 3   50 3   99 $int_hints = $integer::hint_bits || 0x1;
42 3     3   3000 use locale;
  3         783  
  3         18  
43 3   50     7213 $locale_hints = $locale::hint_bits || 0x4;
44             }
45              
46             sub _make_merger {
47 49     49   97 my $types = shift;
48 49         88 my $typessub = shift;
49 49         88 my $vkgen = shift;
50 49         111 my $typeslen = length $types;
51 49         103 my $typesu = "$types\x04";
52 49         80 my @src;
53 49         97 my $i = 0;
54 49         130 for (@_) {
55 2034         3001 my $scratchpad;
56 2034 100       2527 if (my ($v, @k) = &{$vkgen}($scratchpad)) {
  2034         4376  
57 1813 50       12855 if ($typessub) {
58 0         0 @k = $typessub->(@k);
59             }
60             else {
61 1813 50       3894 @k == $typeslen
62             or croak "wrong number of keys generated (expected "
63             .($typeslen - 1).", returned ".(@k - 1).")";
64             }
65 1813         4699 unshift @src, [$v, $_, $scratchpad, @k, $i++];
66 1813         17883 _resort($typesu, \@src);
67             }
68             }
69             sub {
70 49 50   49   373 my $max = @_ ? $_[0] : 1;
71 49         62 my @ret;
72 49   66     275 while (@src and $max--) {
73 41774         56247 my $src = $src[0];
74 41774         62560 push @ret, $src->[VALUE];
75 41774         75322 for ($src[0][FILE]) {
76 41774 100       53362 if (my ($v, @k) = &{$vkgen}($src->[SCRATCHPAD])) {
  41774         92091  
77 39961 50       298442 if ($typessub) {
78 0         0 @k = $typessub->(@k);
79             }
80             else {
81 39961 50       114479 @k == $typeslen
82             or croak "wrong number of keys generated (expected "
83             .($typeslen - 1).", returned ".(@k - 1).")";
84             }
85 39961         59882 $src->[VALUE] = $v;
86 39961         80822 splice @$src, KEY0, $typeslen, @k;
87 39961         603615 _resort($typesu, \@src);
88             }
89             else {
90 1813         16534 shift @src;
91             }
92             }
93             }
94 49 50       9531 wantarray ? @ret : $ret[-1];
95 49         434 };
96             }
97              
98             sub multikeymerger (&@) {
99 0     0 1 0 my $vkgen = shift;
100 0         0 my $types = shift;
101              
102 0 0       0 ref($types) eq 'ARRAY'
103             or croak "Usage: \$merger = multikeymerger { value_key() } \\\@types, \@args";
104              
105 0         0 my $ptypes = Sort::Key::Types::combine_types(@$types);
106 0         0 my $typessub = Sort::Key::Types::combine_sub('@_', undef, @$types);
107              
108 0         0 _make_merger($ptypes, $typessub, $vkgen, @_);
109             }
110              
111             sub keymerger (&@) {
112 16 50   16 1 297472 my $sort = ((caller(0))[8] & $locale_hints)
113             ? LOC_STR_SORT : STR_SORT;
114 16         129 _make_merger( pack(C => $sort), undef, @_ )
115             }
116              
117             sub rkeymerger (&@) {
118 0 0   0 1 0 my $sort = ((caller(0))[8] & $locale_hints)
119             ? LOC_STR_SORT : STR_SORT;
120 0         0 _make_merger( pack(C => $sort|REV_SORT), undef, @_ )
121             }
122              
123             sub nkeymerger (&@) {
124 33 100   33 1 869849 my $sort = ((caller(0))[8] & $int_hints)
125             ? INT_SORT : NUM_SORT;
126 33         239 _make_merger( pack(C => $sort), undef, @_ )
127             }
128              
129             sub rnkeymerger (&@) {
130 0 0   0 1 0 my $sort = ((caller(0))[8] & $int_hints)
131             ? INT_SORT : NUM_SORT;
132 0         0 _make_merger( pack(C => $sort|REV_SORT), undef, @_ )
133             }
134              
135              
136             sub ikeymerger (&@) {
137 0     0 1 0 _make_merger( pack(C => UINT_SORT), undef, @_ )
138             }
139              
140             sub rikeymerger (&@) {
141 0     0 1 0 _make_merger( pack(C => UINT_SORT|REV_SORT), undef, @_ )
142             }
143              
144             sub ukeymerger (&@) {
145 0     0 1 0 _make_merger( pack(C => UINT_SORT), undef, @_ )
146             }
147              
148             sub rukeymerger (&@) {
149 0     0 1 0 _make_merger( pack(C => UINT_SORT|REV_SORT), undef, @_ )
150             }
151              
152             sub _make_file_merger {
153 2     2   4 my $types = shift;
154 2         3 my $kgen = shift;
155 2         4 my $typeslen = length $types;
156 2         6 my $typesu = "$types\x04";
157 2         3 my @src;
158 2         3 my $i = 0;
159 2         5 for my $file (@_) {
160 4         4 my $fh;
161 4 50       22 if (UNIVERSAL::isa($file, 'GLOB')) {
162 0         0 $fh = $file;
163             }
164             else {
165 4 50       186 open $fh, '<', $file
166             or croak "unable to open '$file'";
167             }
168 4         20 local $/ = $/;
169 4         8 local $_;
170 4         128 while(<$fh>) {
171 4 50       10 if (my @k = $kgen->()) {
172 4 50       39 @k == $typeslen
173             or croak "wrong number of return values from merger callback, $typeslen expected, "
174             . scalar(@k) . " found";
175 4         19 unshift @src, [$_, $fh, $/, @k, $i++];
176 4         20 _resort($typesu, \@src);
177 4         18 last;
178             }
179             }
180             }
181              
182 2         5 my $gen;
183             $gen = sub {
184 92 100   92   13943 if (wantarray) {
185 32         42 my @all;
186 32 100       62 my $max = @_ ? $_[0] : 1;
187 32   66     251 while((!defined $max or $max--) and @src) {
      100        
188 60         129 push @all, scalar(&$gen);
189             }
190 32         116 return @all;
191             }
192             else {
193 60 50       111 if (@src) {
194 60         81 my $src = $src[0];
195 60         110 my $old_v = $src->[VALUE];
196 60         108 local *_ = \($src->[VALUE]);
197 60         91 local */ = \($src->[RS]); # emacs syntax higlighting breaks here/;
198 60         79 my $fh = $src->[FILE];
199 60         239 while(<$fh>) {
200 56 50       60 if (my @k = &{$kgen}) {
  56         127  
201 56 50       399 @k == $typeslen
202             or croak "wrong number of return values from merger callback, $typeslen expected, "
203             . scalar(@k) . " found";
204 56         79 $src->[VALUE] = $_;
205 56         122 splice @$src, KEY0, $typeslen, @k;
206 56         175 _resort($typesu, \@src);
207 56         491 return $old_v;
208             }
209             }
210 4         7 shift @src;
211 4         123 return $old_v;
212             }
213             return undef
214 0         0 }
215 2         16 };
216             }
217              
218             sub filekeymerger (&@) {
219 0 0   0 1 0 my $sort = ((caller(0))[8] & $locale_hints)
220             ? LOC_STR_SORT : STR_SORT;
221 0         0 _make_file_merger( pack(C => $sort), @_ )
222             }
223              
224             sub rfilekeymerger (&@) {
225 0 0   0 1 0 my $sort = ((caller(0))[8] & $locale_hints)
226             ? LOC_STR_SORT : STR_SORT;
227 0         0 _make_file_merger( pack(C => $sort|REV_SORT), @_ )
228             }
229              
230             sub nfilekeymerger (&@) {
231 2 50   2 1 38 my $sort = ((caller(0))[8] & $int_hints)
232             ? INT_SORT : NUM_SORT;
233 2         17 _make_file_merger( pack(C => $sort), @_ )
234             }
235              
236             sub rnfilekeymerger (&@) {
237 0 0   0 1   my $sort = ((caller(0))[8] & $int_hints)
238             ? INT_SORT : NUM_SORT;
239 0           _make_file_merger( pack(C => $sort|REV_SORT), @_ )
240             }
241              
242             sub ifilekeymerger (&@) {
243 0     0 1   _make_file_merger( pack(C => INT_SORT), @_ )
244             }
245              
246             sub rifilekeymerger (&@) {
247 0     0 1   _make_file_merger( pack(C => INT_SORT|REV_SORT), @_ )
248             }
249              
250             sub ufilekeymerger (&@) {
251 0     0 1   _make_file_merger( pack(C => INT_SORT), @_ )
252             }
253              
254             sub rufilekeymerger (&@) {
255 0     0 1   _make_file_merger( pack(C => INT_SORT|REV_SORT), @_ )
256             }
257              
258              
259             1;
260             __END__