File Coverage

blib/lib/Set/IntSpan/Fast/XS.pm
Criterion Covered Total %
statement 83 89 93.2
branch 11 14 78.5
condition 3 3 100.0
subroutine 16 18 88.8
pod 0 3 0.0
total 113 127 88.9


line stmt bran cond sub pod time code
1             package Set::IntSpan::Fast::XS;
2              
3             require 5.008;
4              
5 8     8   328670 use strict;
  8         23  
  8         338  
6 8     8   43 use warnings;
  8         15  
  8         339  
7 8     8   48 use Carp;
  8         28  
  8         814  
8 8     8   48 use List::Util qw( max );
  8         15  
  8         1599  
9 8     8   26174 use Data::Swap;
  8         11767  
  8         698  
10 8     8   157 use base qw( DynaLoader Set::IntSpan::Fast::PP );
  8         15  
  8         10249  
11              
12             =head1 NAME
13              
14             Set::IntSpan::Fast::XS - Faster Set::IntSpan::Fast
15              
16             =head1 VERSION
17              
18             This document describes Set::IntSpan::Fast::XS version 0.05
19              
20             =head1 SYNOPSIS
21              
22             use Set::IntSpan::Fast::XS;
23            
24             my $set = Set::IntSpan::Fast::XS->new();
25             $set->add(1, 3, 5, 7, 9);
26             $set->add_range(100, 1_000_000);
27             print $set->as_string(), "\n"; # prints 1,3,5,7,9,100-1000000
28              
29             =head1 DESCRIPTION
30              
31             This is a drop in replacement XS based version of L.
32             See that module for details of the interface.
33              
34             =cut
35              
36             BEGIN {
37 8     8   65443 our $VERSION = '0.05';
38 8         13082 bootstrap Set::IntSpan::Fast::XS $VERSION;
39              
40             }
41              
42             sub _lr {
43 59     59   68 my $self = shift;
44 59         65 my $ar = shift;
45 59         131 my @list = sort { $a <=> $b } @$ar;
  107         134  
46 59         73 my @ranges = ();
47 59         64 my $count = scalar( @list );
48 59         154 my $pos = 0;
49 59         123 while ( $pos < $count ) {
50 108         133 my $end = $pos + 1;
51 108   100     518 $end++ while $end < $count && $list[$end] <= $list[ $end - 1 ] + 1;
52 108         232 push @ranges, ( $list[$pos], $list[ $end - 1 ] + 1 );
53 108         264 $pos = $end;
54             }
55              
56 59         283 return \@ranges;
57             }
58              
59             sub _tidy_ranges {
60 16153     16153   23118 my ( $self, $r ) = @_;
61 16153         33682 my @r = @$r;
62 16153         22175 my @s = ();
63 16153         39689 for ( my $p = 0; $p <= $#r; $p += 2 ) {
64 23309         99321 push @s, [ $r[$p], $r[ $p + 1 ] ];
65             }
66 16153 50       45417 my @t = sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] } @s;
  18875         59540  
67              
68 16153         39691 for ( my $p = 1; $p <= $#t; ) {
69 7215 100       25286 if ( $t[ $p - 1 ][1] >= $t[$p][0] ) {
70 7021         21705 $t[ $p - 1 ][1] = max( $t[ $p - 1 ][1], $t[$p][1] );
71 7021         23305 splice @t, $p, 1;
72             }
73             else {
74 194         501 $p++;
75             }
76             }
77              
78 16153         23680 return [ map { $_->[0], $_->[1] + 1 } @t ];
  16288         112830  
79             }
80              
81             sub add {
82 59     59 0 14740 my $self = shift;
83 59 50       129 if ( @_ < 100 ) {
84 59         165 $self->_add_splice( @_ );
85             }
86             else {
87 0         0 $self->_add_merge( @_ );
88             }
89 59         165 return;
90             }
91              
92             sub add_range {
93 16153     16153 0 6368335 my $self = shift;
94 16153 50       44576 if ( @_ < 100 ) {
95 16153         33924 $self->_add_range_splice( @_ );
96             }
97             else {
98 0         0 $self->_add_range_merge( @_ );
99             }
100 16153         62649 return;
101             }
102              
103             sub _add_merge {
104 0     0   0 my $self = shift;
105 0         0 $self->_merge_and_swap( $self->_lr( \@_ ), $self );
106             }
107              
108             sub _add_range_merge {
109 0     0   0 my $self = shift;
110 0         0 $self->_merge_and_swap( $self->_tidy_ranges( \@_ ), $self );
111             }
112              
113             sub _splice {
114 16212     16212   32687 my ( $self, $from, $into ) = @_;
115              
116 16212         25517 my $class = ref $self;
117              
118 16212 100       37933 if ( @$from > @$into ) {
119 2615         6056 swap $from, $into;
120 2615         5675 bless $into, $class;
121             }
122              
123 16212         20623 my $count = scalar @$from;
124              
125 16212         41349 for ( my $p = 0; $p < $count; $p += 2 ) {
126 13614         24227 my ( $from, $to ) = ( $from->[$p], $from->[ $p + 1 ] );
127              
128 13614         47775 my $fpos = $self->_find_pos( $from );
129 13614         40206 my $tpos = $self->_find_pos( $to + 1, $fpos );
130              
131 13614 100       37144 $from = $into->[ --$fpos ] if ( $fpos & 1 );
132 13614 100       26842 $to = $into->[ $tpos++ ] if ( $tpos & 1 );
133              
134 13614         61549 splice @$into, $fpos, $tpos - $fpos, ( $from, $to );
135             }
136              
137 16212         28021 swap $self, $into;
138 16212         35800 bless $self, $class;
139              
140 16212         47392 return;
141             }
142              
143             sub _add_splice {
144 59     59   72 my $self = shift;
145 59         138 $self->_splice( $self->_lr( \@_ ), $self );
146             }
147              
148             sub _add_range_splice {
149 16153     16153   17709 my $self = shift;
150 16153         36651 $self->_splice( $self->_tidy_ranges( \@_ ), $self );
151             }
152              
153             sub _merge_and_swap {
154 517     517   562 my $self = shift;
155 517         4356 my $new = $self->_merge( @_ );
156              
157 517         859 my $class = ref $self;
158 517         991 swap $self, $new;
159 517         1033 bless $self, $class;
160              
161 517         2295 return;
162             }
163              
164             sub merge {
165 259     259 0 108961 my $self = shift;
166 259         727 $self->_merge_and_swap( $self, $_ ) for @_;
167             }
168              
169             1;
170              
171             __END__