File Coverage

blib/lib/List/Range/Search/Binary.pm
Criterion Covered Total %
statement 35 35 100.0
branch 8 12 66.6
condition 1 2 50.0
subroutine 7 7 100.0
pod 2 2 100.0
total 53 58 91.3


line stmt bran cond sub pod time code
1             package List::Range::Search::Binary;
2 2     2   896 use strict;
  2         3  
  2         42  
3 2     2   6 use warnings;
  2         2  
  2         42  
4              
5 2     2   6 use Class::Accessor::Lite ro => [qw/ranges/];
  2         2  
  2         9  
6              
7             sub new {
8 1     1 1 7 my ($class, $set, $opt) = @_;
9 1   50     4 $opt ||= {};
10              
11 1         4 my $ranges = $class->_normalize($set->ranges, $opt);
12 1         4 return bless {
13             ranges => $ranges,
14             } => $class;
15             }
16              
17             sub _normalize {
18 1     1   5 my ($class, $ranges, $opt) = @_;
19             my $sorted = $opt->{no_sort} ? $ranges : [
20 1 50       6 sort { $a->lower <=> $b->lower || $a->upper <=> $b->upper } @$ranges
  9 50       45  
21             ];
22 1 50       9 return $opt->{no_verify} ? $sorted : $class->_verify($sorted);
23             }
24              
25             sub _verify {
26 1     1   2 my ($class, $ranges) = @_;
27 1         1 for my $i (0..$#{$ranges}-1) {
  1         3  
28 5         22 my $before = $ranges->[$i];
29 5         4 my $after = $ranges->[$i+1];
30 5 50       7 die "Binary search does not support to search in the crossed ranges"
31             if $after->lower <= $before->upper;
32             }
33 1         5 return $ranges;
34             }
35              
36             sub find {
37 7     7 1 5050 my ($self, $value) = @_;
38              
39 7         8 my @ranges = @{ $self->{ranges} };
  7         15  
40 7         15 while (@ranges) {
41 18         24 my $point = int($#ranges / 2);
42 18         17 my $range = $ranges[$point];
43 18 100       27 if ($value < $range->lower) {
    100          
44 4         27 splice @ranges, $point;
45             }
46             elsif ($value > $range->upper) {
47 8         61 splice @ranges, 0, $point + 1;
48             }
49             else {
50             # includes
51 6         52 return $range;
52             }
53             }
54              
55             # not found
56 1         4 return undef; ## no critic
57             }
58              
59             1;
60             __END__