| 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__ |