File Coverage

blib/lib/Sort/DJB/Pure.pm
Criterion Covered Total %
statement 129 146 88.3
branch 31 38 81.5
condition n/a
subroutine 13 16 81.2
pod 0 12 0.0
total 173 212 81.6


line stmt bran cond sub pod time code
1             package Sort::DJB::Pure;
2              
3 1     1   511 use strict;
  1         2  
  1         42  
4 1     1   3 use warnings;
  1         2  
  1         1275  
5              
6             our $VERSION = '0.2';
7              
8             # Pure Perl implementation of the djbsort bitonic sorting network algorithm.
9             # This is a direct translation of djbsort's portable4/sort.c.
10              
11             sub _minmax {
12             # Swap so that $_[0] <= $_[1]
13 5558 100   5558   8643 if ($_[0] > $_[1]) {
14 2626         4628 @_[0, 1] = @_[1, 0];
15             }
16             }
17              
18             sub _int_sort {
19 25     25   40 my ($x) = @_;
20 25         34 my $n = scalar @$x;
21              
22 25 100       60 return if $n < 2;
23              
24 23         27 my $top = 1;
25 23         49 while ($top < $n - $top) {
26 62         114 $top += $top;
27             }
28              
29 23         79 for (my $p = $top; $p >= 1; $p >>= 1) {
30 85         107 my $i = 0;
31 85         225 while ($i + 2 * $p <= $n) {
32 1230         1966 for (my $j = $i; $j < $i + $p; ++$j) {
33 4591         5962 _minmax($x->[$j], $x->[$j + $p]);
34             }
35 1230         2046 $i += 2 * $p;
36             }
37 85         151 for (my $j = $i; $j < $n - $p; ++$j) {
38 967         1044 _minmax($x->[$j], $x->[$j + $p]);
39             }
40              
41 85         92 $i = 0;
42 85         101 my $j = 0;
43             QLOOP:
44 85         205 for (my $q = $top; $q > $p; $q >>= 1) {
45 147 100       215 if ($j != $i) {
46 7         8 for (;;) {
47 52 50       60 last QLOOP if $j == $n - $q;
48 52         53 my $a = $x->[$j + $p];
49 52         69 for (my $r = $q; $r > $p; $r >>= 1) {
50 104 100       156 if ($a > $x->[$j + $r]) {
51 42         72 ($a, $x->[$j + $r]) = ($x->[$j + $r], $a);
52             }
53             }
54 52         50 $x->[$j + $p] = $a;
55 52         45 ++$j;
56 52 100       64 if ($j == $i + $p) {
57 7         9 $i += 2 * $p;
58 7         9 last;
59             }
60             }
61             }
62 147         242 while ($i + $p <= $n - $q) {
63 1187         1737 for (my $jj = $i; $jj < $i + $p; ++$jj) {
64 4361         4983 my $a = $x->[$jj + $p];
65 4361         6012 for (my $r = $q; $r > $p; $r >>= 1) {
66 19409 100       32944 if ($a > $x->[$jj + $r]) {
67 5019         9729 ($a, $x->[$jj + $r]) = ($x->[$jj + $r], $a);
68             }
69             }
70 4361         7275 $x->[$jj + $p] = $a;
71             }
72 1187         1874 $i += 2 * $p;
73             }
74             # now i + p > n - q
75 147         187 $j = $i;
76 147         345 while ($j < $n - $q) {
77 74         84 my $a = $x->[$j + $p];
78 74         98 for (my $r = $q; $r > $p; $r >>= 1) {
79 170 100       275 if ($a > $x->[$j + $r]) {
80 49         103 ($a, $x->[$j + $r]) = ($x->[$j + $r], $a);
81             }
82             }
83 74         72 $x->[$j + $p] = $a;
84 74         132 ++$j;
85             }
86             }
87             }
88             }
89              
90             sub sort_int32 {
91 13     13 0 214305 my ($aref) = @_;
92 13         99 my @copy = @$aref;
93             # Clamp to int32 range
94 13         27 for my $v (@copy) {
95 1225         1020 $v = int($v);
96 1225 50       1354 $v = -2147483648 if $v < -2147483648;
97 1225 50       1439 $v = 2147483647 if $v > 2147483647;
98             }
99 13         37 _int_sort(\@copy);
100 13         51 return \@copy;
101             }
102              
103             sub sort_int32down {
104 2     2 0 2976 my ($aref) = @_;
105 2         4 my @copy = @$aref;
106 2         4 for my $v (@copy) {
107 10         11 $v = int($v);
108 10 50       12 $v = -2147483648 if $v < -2147483648;
109 10 50       12 $v = 2147483647 if $v > 2147483647;
110             }
111             # XOR with -1 (bitwise NOT) to reverse order, sort, then undo
112             # In Perl we just reverse the comparison by negating
113 2         6 $_ = ~$_ & 0xFFFFFFFF for @copy;
114             # Treat as signed int32 after XOR
115 2         3 for my $v (@copy) {
116 10 100       13 $v = $v - 4294967296 if $v >= 2147483648;
117             }
118 2         6 _int_sort(\@copy);
119             # Undo: XOR with -1 again
120 2         2 for my $v (@copy) {
121 10 100       14 $v = ($v < 0 ? $v + 4294967296 : $v);
122 10         6 $v = ~$v & 0xFFFFFFFF;
123 10 100       15 $v = $v - 4294967296 if $v >= 2147483648;
124             }
125 2         4 return \@copy;
126             }
127              
128             sub sort_uint32 {
129 2     2 0 2949 my ($aref) = @_;
130 2         5 my @copy = @$aref;
131 2         20 for my $v (@copy) {
132 9         10 $v = int($v) & 0xFFFFFFFF;
133             # XOR with sign bit to convert to signed for sorting
134 9         10 $v ^= 0x80000000;
135 9 100       20 $v = $v - 4294967296 if $v >= 2147483648;
136             }
137 2         6 _int_sort(\@copy);
138             # Undo conversion
139 2         4 for my $v (@copy) {
140 9 100       14 $v = ($v < 0 ? $v + 4294967296 : $v);
141 9         11 $v ^= 0x80000000;
142             }
143 2         5 return \@copy;
144             }
145              
146             sub sort_uint32down {
147 1     1 0 1985 my ($aref) = @_;
148 1         2 my @copy = @$aref;
149 1         3 for my $v (@copy) {
150 5         7 $v = int($v) & 0xFFFFFFFF;
151             # XOR with sign bit, then XOR with -1 for descending
152 5         3 $v ^= 0x80000000;
153 5         6 $v = ~$v & 0xFFFFFFFF;
154 5 50       21 $v = $v - 4294967296 if $v >= 2147483648;
155             }
156 1         4 _int_sort(\@copy);
157             # Undo
158 1         3 for my $v (@copy) {
159 5 50       9 $v = ($v < 0 ? $v + 4294967296 : $v);
160 5         6 $v = ~$v & 0xFFFFFFFF;
161 5         6 $v ^= 0x80000000;
162             }
163 1         4 return \@copy;
164             }
165              
166             sub sort_int64 {
167 2     2 0 4389 my ($aref) = @_;
168 2         6 my @copy = @$aref;
169 2         4 for my $v (@copy) {
170 10         14 $v = int($v);
171             }
172 2         7 _int_sort(\@copy);
173 2         5 return \@copy;
174             }
175              
176             sub sort_int64down {
177 1     1 0 2204 my ($aref) = @_;
178 1         3 my @copy = map { int($_) } @$aref;
  5         10  
179             # Negate to reverse, sort, negate back
180 1         6 $_ = -$_ - 1 for @copy;
181 1         4 _int_sort(\@copy);
182 1         4 $_ = -$_ - 1 for @copy;
183 1         4 return \@copy;
184             }
185              
186             sub sort_uint64 {
187 1     1 0 2227 my ($aref) = @_;
188             # For uint64, use numeric sort since Perl handles big numbers
189 1         3 my @copy = map { int($_) } @$aref;
  5         11  
190 1         5 _int_sort(\@copy);
191 1         6 return \@copy;
192             }
193              
194             sub sort_uint64down {
195 0     0 0 0 my ($aref) = @_;
196 0         0 my @copy = map { -int($_) - 1 } @$aref;
  0         0  
197 0         0 _int_sort(\@copy);
198 0         0 $_ = -$_ - 1 for @copy;
199 0         0 return \@copy;
200             }
201              
202             sub sort_float64 {
203 2     2 0 3982 my ($aref) = @_;
204 2         5 my @copy = map { $_ + 0.0 } @$aref;
  10         17  
205 2         23 _int_sort(\@copy);
206 2         7 return \@copy;
207             }
208              
209             sub sort_float64down {
210 1     1 0 2154 my ($aref) = @_;
211 1         3 my @copy = map { -($_ + 0.0) } @$aref;
  5         40  
212 1         4 _int_sort(\@copy);
213 1         4 $_ = -$_ for @copy;
214 1         4 return \@copy;
215             }
216              
217             sub sort_float32 {
218 0     0 0   my ($aref) = @_;
219             # Perl doesn't have native float32; use float64 comparison (same order)
220 0           my @copy = map { $_ + 0.0 } @$aref;
  0            
221 0           _int_sort(\@copy);
222 0           return \@copy;
223             }
224              
225             sub sort_float32down {
226 0     0 0   my ($aref) = @_;
227 0           my @copy = map { -($_ + 0.0) } @$aref;
  0            
228 0           _int_sort(\@copy);
229 0           $_ = -$_ for @copy;
230 0           return \@copy;
231             }
232              
233             1;
234              
235             __END__