| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Set::IntSpan; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 20 |  |  | 20 |  | 18761 | use 5; | 
|  | 20 |  |  |  |  | 82 |  | 
|  | 20 |  |  |  |  | 1565 |  | 
| 4 | 20 |  |  | 20 |  | 23293 | use if $Set::IntSpan::integer, qw(integer); | 
|  | 20 |  |  |  |  | 188 |  | 
|  | 20 |  |  |  |  | 98 |  | 
| 5 | 20 |  |  | 20 |  | 1772 | use strict; | 
|  | 20 |  |  |  |  | 40 |  | 
|  | 20 |  |  |  |  | 716 |  | 
| 6 | 20 |  |  | 20 |  | 97 | use base qw(Exporter); | 
|  | 20 |  |  |  |  | 30 |  | 
|  | 20 |  |  |  |  | 2500 |  | 
| 7 | 20 |  |  | 20 |  | 113 | use Carp; | 
|  | 20 |  |  |  |  | 33 |  | 
|  | 20 |  |  |  |  | 4067 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | our $VERSION   = '1.19'; | 
| 10 |  |  |  |  |  |  | our @EXPORT_OK = qw(grep_set map_set grep_spans map_spans); | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | use overload | 
| 13 |  |  |  |  |  |  | '+'    => 'union'     , | 
| 14 |  |  |  |  |  |  | '-'    => 'diff'      , | 
| 15 |  |  |  |  |  |  | '*'    => 'intersect' , | 
| 16 |  |  |  |  |  |  | '^'    => 'xor'       , | 
| 17 |  |  |  |  |  |  | '~'    => 'complement', | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | '+='   => 'U'	  , | 
| 20 |  |  |  |  |  |  | '-='   => 'D'	  , | 
| 21 |  |  |  |  |  |  | '*='   => 'I'	  , | 
| 22 |  |  |  |  |  |  | '^='   => 'X'	  , | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | 'eq'   => 'set_eq' 	  , | 
| 25 |  |  |  |  |  |  | 'ne'   => 'set_ne' 	  , | 
| 26 |  |  |  |  |  |  | 'lt'   => 'set_lt' 	  , | 
| 27 |  |  |  |  |  |  | 'le'   => 'set_le' 	  , | 
| 28 |  |  |  |  |  |  | 'gt'   => 'set_gt' 	  , | 
| 29 |  |  |  |  |  |  | 'ge'   => 'set_ge' 	  , | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | '<=>'  => 'spaceship' , | 
| 32 |  |  |  |  |  |  | 'cmp'  => 'spaceship' , | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | '""'   => 'run_list'  , | 
| 35 | 20 |  |  | 20 |  | 51337 | 'bool' => sub { not shift->empty }; | 
|  | 20 |  |  | 3 |  | 26379 |  | 
|  | 20 |  |  |  |  | 217 |  | 
|  | 3 |  |  |  |  | 21 |  | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | sub _reorder # restore the order of args that are reversed by operator overloads | 
| 38 |  |  |  |  |  |  | { | 
| 39 | 278 | 100 |  | 278 |  | 569 | if ($_[2]) | 
| 40 |  |  |  |  |  |  | { | 
| 41 | 5 |  |  |  |  | 6 | my $temp = $_[0]; | 
| 42 | 5 |  |  |  |  | 6 | $_[0] = $_[1]; | 
| 43 | 5 |  |  |  |  | 8 | $_[1] = $temp; | 
| 44 |  |  |  |  |  |  | } | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | sub set_eq | 
| 48 |  |  |  |  |  |  | { | 
| 49 | 52 |  |  | 52 | 0 | 241 | my($a, $set_spec) = @_; | 
| 50 | 52 |  |  |  |  | 104 | my $b = $a->_real_set($set_spec); | 
| 51 | 52 |  |  |  |  | 106 | $a->equal($b) | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | sub set_le | 
| 55 |  |  |  |  |  |  | { | 
| 56 | 7 |  |  | 7 | 0 | 37 | my($a, $set_spec, $reverse) = @_; | 
| 57 | 7 |  |  |  |  | 11 | my $b = $a->_real_set($set_spec); | 
| 58 | 7 |  |  |  |  | 12 | _reorder($a, $b, $reverse); | 
| 59 | 7 |  |  |  |  | 13 | $a->subset($b) | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | sub set_ge | 
| 63 |  |  |  |  |  |  | { | 
| 64 | 7 |  |  | 7 | 0 | 33 | my($a, $set_spec, $reverse) = @_; | 
| 65 | 7 |  |  |  |  | 14 | my $b = $a->_real_set($set_spec); | 
| 66 | 7 |  |  |  |  | 14 | _reorder($a, $b, $reverse); | 
| 67 | 7 |  |  |  |  | 18 | $a->superset($b) | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 4 |  |  | 4 | 0 | 28 | sub set_ne {             not &set_eq } | 
| 71 | 3 | 100 |  | 3 | 0 | 25 | sub set_lt { &set_le and not &set_eq } | 
| 72 | 3 | 100 |  | 3 | 0 | 26 | sub set_gt { &set_ge and not &set_eq } | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | sub set_cmp | 
| 76 |  |  |  |  |  |  | { | 
| 77 | 0 |  |  | 0 | 0 | 0 | my($a, $b, $reverse) = @_; | 
| 78 | 0 |  |  |  |  | 0 | $b = $a->_real_set($b); | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 0 |  |  |  |  | 0 | _reorder($a, $b, $reverse); | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 0 | 0 |  |  |  | 0 | $a->equal($b) ? 0 : 1; | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub spaceship | 
| 87 |  |  |  |  |  |  | { | 
| 88 | 21 |  |  | 21 | 0 | 130 | my($a, $b, $reverse) = @_; | 
| 89 | 21 | 50 |  |  |  | 51 | ref $a and $a = $a->size; | 
| 90 | 21 | 100 |  |  |  | 33 | ref $b and $b = $b->size; | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 21 |  |  |  |  | 32 | _reorder($a, $b, $reverse); | 
| 93 |  |  |  |  |  |  |  | 
| 94 | 21 | 100 |  |  |  | 36 | $a ==  $b and return  0; | 
| 95 | 14 | 100 |  |  |  | 23 | $a <   0  and return  1; | 
| 96 | 12 | 100 |  |  |  | 18 | $b <   0  and return -1; | 
| 97 | 11 |  |  |  |  | 23 | $a <=> $b | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | $Set::IntSpan::Empty_String = '-'; | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | sub new | 
| 105 |  |  |  |  |  |  | { | 
| 106 | 3427 |  |  | 3427 | 1 | 41877 | my($this, $set_spec, @set_specs) = @_; | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 3427 |  | 66 |  |  | 11343 | my $class = ref($this) || $this; | 
| 109 | 3427 |  |  |  |  | 7622 | my $set   = bless { }, $class; | 
| 110 | 3427 |  |  |  |  | 9131 | $set->{empty_string} = \$Set::IntSpan::Empty_String; | 
| 111 | 3427 |  |  |  |  | 8194 | $set->copy($set_spec); | 
| 112 |  |  |  |  |  |  |  | 
| 113 | 3416 |  |  |  |  | 7426 | while (@set_specs) | 
| 114 |  |  |  |  |  |  | { | 
| 115 | 13 |  |  |  |  | 45 | $set = $set->union(shift @set_specs); | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | $set | 
| 119 | 3416 |  |  |  |  | 12991 | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | sub valid | 
| 123 |  |  |  |  |  |  | { | 
| 124 | 11 |  |  | 11 | 1 | 243 | my($this, $run_list) = @_; | 
| 125 | 11 |  | 33 |  |  | 42 | my $class = ref($this) || $this; | 
| 126 | 11 |  |  |  |  | 20 | my $set   = new $class; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 11 |  |  |  |  | 19 | eval { $set->_copy_run_list($run_list) }; | 
|  | 11 |  |  |  |  | 24 |  | 
| 129 | 11 | 50 |  |  |  | 61 | $@ ? 0 : 1 | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | sub copy | 
| 134 |  |  |  |  |  |  | { | 
| 135 | 3427 |  |  | 3427 | 1 | 4498 | my($set, $set_spec) = @_; | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 3427 | 100 |  |  |  | 7400 | SWITCH: | 
| 138 |  |  |  |  |  |  | { | 
| 139 | 3427 |  |  |  |  | 12347 | defined $set_spec            or  $set->_copy_empty   (         ), last; | 
| 140 | 2498 | 100 |  |  |  | 10125 | ref     $set_spec            or  $set->_copy_run_list($set_spec), last; | 
| 141 | 98 | 100 |  |  |  | 304 | ref     $set_spec eq 'ARRAY' and $set->_copy_array   ($set_spec), last; | 
| 142 | 50 |  |  |  |  | 118 | $set->_copy_set     ($set_spec)      ; | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | $set | 
| 146 | 3416 |  |  |  |  | 4690 | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | sub _copy_empty			# makes $set the empty set | 
| 150 |  |  |  |  |  |  | { | 
| 151 | 3340 |  |  | 3340 |  | 4072 | my $set = shift; | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 3340 |  |  |  |  | 5677 | $set->{negInf} = 0; | 
| 154 | 3340 |  |  |  |  | 4595 | $set->{posInf} = 0; | 
| 155 | 3340 |  |  |  |  | 7175 | $set->{edges } = []; | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | sub _copy_array			# copies an array into a set | 
| 160 |  |  |  |  |  |  | { | 
| 161 | 48 |  |  | 48 |  | 67 | my($set, $array) = @_; | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 48 |  |  |  |  | 87 | my @spans    = 		      grep { ref     } @$array; | 
|  | 110 |  |  |  |  | 227 |  | 
| 164 | 48 |  |  |  |  | 75 | my @elements = sort { $a <=> $b } grep { not ref } @$array; | 
|  | 86 |  |  |  |  | 129 |  | 
|  | 110 |  |  |  |  | 238 |  | 
| 165 |  |  |  |  |  |  |  | 
| 166 | 48 |  |  |  |  | 1617 | my @span; | 
| 167 | 48 |  |  |  |  | 79 | for my $e (@elements) | 
| 168 |  |  |  |  |  |  | { | 
| 169 | 74 | 100 | 100 |  |  | 524 | if (@span==0) | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | { | 
| 171 | 23 |  |  |  |  | 44 | push @span, $e; | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  | elsif (@span==1 and $e==$span[0]+1) | 
| 174 |  |  |  |  |  |  | { | 
| 175 | 19 |  |  |  |  | 34 | push @span, $e; | 
| 176 |  |  |  |  |  |  | } | 
| 177 |  |  |  |  |  |  | elsif (@span==1 and $e >$span[0]+1) | 
| 178 |  |  |  |  |  |  | { | 
| 179 | 6 |  |  |  |  | 15 | push @spans, [ $span[0], $span[0] ]; | 
| 180 | 6 |  |  |  |  | 14 | @span = ($e); | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  | elsif (@span==2 and $e==$span[1]+1) | 
| 183 |  |  |  |  |  |  | { | 
| 184 | 11 |  |  |  |  | 27 | $span[1] = $e; | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  | elsif (@span==2 and $e >$span[1]+1) | 
| 187 |  |  |  |  |  |  | { | 
| 188 | 6 |  |  |  |  | 15 | push @spans, [ @span ]; | 
| 189 | 6 |  |  |  |  | 15 | @span = ($e); | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 48 | 100 |  |  |  | 117 | @span==1 and push @spans, [ $span[0], $span[0] ]; | 
| 194 | 48 | 100 |  |  |  | 103 | @span==2 and push @spans, [ @span ]; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 48 |  |  |  |  | 123 | $set->_insert_spans(\@spans) | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | sub bySpan | 
| 200 |  |  |  |  |  |  | { | 
| 201 | 95 |  |  | 95 | 0 | 125 | my($al, $au) = @$a; | 
| 202 | 95 |  |  |  |  | 121 | my($bl, $bu) = @$b; | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 95 | 100 | 100 |  |  | 371 | if (defined $al && defined $bl) { return $al <=> $bl; } | 
|  | 77 | 100 |  |  |  | 158 |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 205 | 5 |  |  |  |  | 9 | elsif (defined $al               ) { return  1;          } | 
| 206 | 12 |  |  |  |  | 20 | elsif (               defined $bl) { return -1;          } | 
| 207 | 0 |  |  |  |  | 0 | elsif (defined $au               ) { return -1;          } | 
| 208 | 0 |  |  |  |  | 0 | elsif (               defined $bu) { return  1;          } | 
| 209 | 1 |  |  |  |  | 4 | else                               { return  0;          } | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | sub _insert_spans | 
| 213 |  |  |  |  |  |  | { | 
| 214 | 108 |  |  | 108 |  | 128 | my($set, $spans) = @_; | 
| 215 |  |  |  |  |  |  |  | 
| 216 | 108 |  |  |  |  | 111 | my @edges; | 
| 217 | 108 |  |  |  |  | 152 | $set->{negInf} = 0; | 
| 218 | 108 |  |  |  |  | 147 | $set->{posInf} = 0; | 
| 219 | 108 |  |  |  |  | 157 | $set->{edges } = \@edges; | 
| 220 |  |  |  |  |  |  |  | 
| 221 | 108 |  |  |  |  | 331 | my @spans = sort bySpan @$spans; | 
| 222 |  |  |  |  |  |  |  | 
| 223 | 108 | 100 | 100 |  |  | 1001 | if (@spans and not defined $spans[0][0]) | 
| 224 |  |  |  |  |  |  | { | 
| 225 | 24 |  |  |  |  | 40 | $set->{negInf} = 1; | 
| 226 | 24 |  |  |  |  | 28 | my $span = shift @spans; | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 24 | 100 |  |  |  | 59 | if (not defined $span->[1]) | 
| 229 |  |  |  |  |  |  | { | 
| 230 | 8 |  |  |  |  | 53 | $set->{posInf} = 1; | 
| 231 | 8 |  |  |  |  | 30 | return $set; | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  |  | 
| 234 | 16 |  |  |  |  | 94 | push @edges, $span->[1]; | 
| 235 |  |  |  |  |  |  |  | 
| 236 | 16 |  | 66 |  |  | 81 | while (@spans and not defined $spans[0][0]) | 
| 237 |  |  |  |  |  |  | { | 
| 238 | 0 |  |  |  |  | 0 | my $span = shift @spans; | 
| 239 | 0 | 0 |  |  |  | 0 | $edges[0] = $span->[1] if $edges[0] < $span->[1]; | 
| 240 |  |  |  |  |  |  | } | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  |  | 
| 243 | 100 |  |  |  |  | 172 | for (@spans) { $_->[0]--; } | 
|  | 130 |  |  |  |  | 225 |  | 
| 244 |  |  |  |  |  |  |  | 
| 245 | 100 | 100 | 100 |  |  | 386 | if (@spans and not @edges) | 
| 246 |  |  |  |  |  |  | { | 
| 247 | 65 |  |  |  |  | 199 | my $span = shift @spans; | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 65 | 100 |  |  |  | 128 | if (defined $span->[1]) | 
| 250 |  |  |  |  |  |  | { | 
| 251 | 59 |  |  |  |  | 195 | push @edges, @$span; | 
| 252 |  |  |  |  |  |  | } | 
| 253 |  |  |  |  |  |  | else | 
| 254 |  |  |  |  |  |  | { | 
| 255 | 6 |  |  |  |  | 14 | push @edges, $span->[0]; | 
| 256 | 6 |  |  |  |  | 10 | $set->{posInf} = 1; | 
| 257 | 6 |  |  |  |  | 23 | return $set; | 
| 258 |  |  |  |  |  |  | } | 
| 259 |  |  |  |  |  |  | } | 
| 260 |  |  |  |  |  |  |  | 
| 261 | 94 |  | 100 |  |  | 316 | while (@spans and defined $spans[0][1]) | 
| 262 |  |  |  |  |  |  | { | 
| 263 | 55 |  |  |  |  | 69 | my $span = shift @spans; | 
| 264 | 55 | 100 |  |  |  | 100 | if ($edges[-1] < $span->[0]) | 
| 265 |  |  |  |  |  |  | { | 
| 266 | 47 |  |  |  |  | 175 | push @edges, @$span; | 
| 267 |  |  |  |  |  |  | } | 
| 268 |  |  |  |  |  |  | else | 
| 269 |  |  |  |  |  |  | { | 
| 270 | 8 | 100 |  |  |  | 55 | $edges[-1] = $span->[1] if $edges[-1] < $span->[1]; | 
| 271 |  |  |  |  |  |  | } | 
| 272 |  |  |  |  |  |  | } | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 94 | 100 |  |  |  | 183 | if (@spans) | 
| 275 |  |  |  |  |  |  | { | 
| 276 | 10 |  |  |  |  | 24 | $set->{posInf} = 1; | 
| 277 | 10 |  |  |  |  | 126 | my $span = shift @spans; | 
| 278 |  |  |  |  |  |  |  | 
| 279 | 10 | 100 |  |  |  | 23 | if ($edges[-1] < $span->[0]) | 
| 280 |  |  |  |  |  |  | { | 
| 281 | 6 |  |  |  |  | 11 | push @edges, $span->[0]; | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  | else | 
| 284 |  |  |  |  |  |  | { | 
| 285 | 4 |  |  |  |  | 7 | pop @edges; | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 | 94 |  |  |  |  | 352 | return $set | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | sub _copy_set			# copies one set to another | 
| 294 |  |  |  |  |  |  | { | 
| 295 | 50 |  |  | 50 |  | 58 | my($dest, $src) = @_; | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 50 |  |  |  |  | 87 | $dest->{negInf} =     $src->{negInf}; | 
| 298 | 50 |  |  |  |  | 73 | $dest->{posInf} =     $src->{posInf}; | 
| 299 | 50 |  |  |  |  | 74 | $dest->{edges } = [ @{$src->{edges }} ]; | 
|  | 50 |  |  |  |  | 159 |  | 
| 300 |  |  |  |  |  |  | } | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | sub _copy_run_list		# parses a run list | 
| 304 |  |  |  |  |  |  | { | 
| 305 | 2411 |  |  | 2411 |  | 5657 | my($set, $runList) = @_; | 
| 306 |  |  |  |  |  |  |  | 
| 307 | 2411 |  |  |  |  | 4180 | $set->_copy_empty; | 
| 308 |  |  |  |  |  |  |  | 
| 309 | 2411 |  |  |  |  | 8143 | $runList =~ s/\s|_//g; | 
| 310 | 2411 | 100 |  |  |  | 5195 | return if $runList eq '-';	# empty set | 
| 311 |  |  |  |  |  |  |  | 
| 312 | 2160 |  |  |  |  | 3111 | my($first, $last) = (1, 0);	# verifies order of infinite runs | 
| 313 |  |  |  |  |  |  |  | 
| 314 | 2160 |  |  |  |  | 2350 | my @edges; | 
| 315 | 2160 |  |  |  |  | 5525 | for my $run (split(/,/ , $runList)) | 
| 316 |  |  |  |  |  |  | { | 
| 317 | 3081 | 100 |  |  |  | 6161 | croak "Set::IntSpan::_copy_run_list: Bad order 1: $runList\n" if $last; | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | RUN: | 
| 320 |  |  |  |  |  |  | { | 
| 321 | 3077 |  |  |  |  | 2942 | $run =~ /^ (-?\d+) $/x and do | 
| 322 | 3077 | 100 |  |  |  | 10251 | { | 
| 323 | 652 |  |  |  |  | 1923 | push(@edges, $1-1, $1); | 
| 324 | 652 |  |  |  |  | 1146 | last RUN; | 
| 325 |  |  |  |  |  |  | }; | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | $run =~ /^ (-?\d+) - (-?\d+) $/x and do | 
| 328 | 2425 | 100 |  |  |  | 8244 | { | 
| 329 | 1587 | 100 |  |  |  | 5157 | croak "Set::IntSpan::_copy_run_list: Bad order 2: $runList\n" | 
| 330 |  |  |  |  |  |  | if $1 > $2; | 
| 331 | 1585 |  |  |  |  | 3770 | push(@edges, $1-1, $2); | 
| 332 | 1585 |  |  |  |  | 2249 | last RUN; | 
| 333 |  |  |  |  |  |  | }; | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | $run =~ /^ \( - (-?\d+) $/x and do | 
| 336 | 838 | 100 |  |  |  | 2565 | { | 
| 337 | 293 | 100 |  |  |  | 1016 | croak "Set::IntSpan::_copy_run_list: Bad order 3: $runList\n" | 
| 338 |  |  |  |  |  |  | unless $first; | 
| 339 | 291 |  |  |  |  | 435 | $set->{negInf} = 1; | 
| 340 | 291 |  |  |  |  | 887 | push @edges, $1; | 
| 341 | 291 |  |  |  |  | 427 | last RUN; | 
| 342 |  |  |  |  |  |  | }; | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | $run =~ /^ (-?\d+) - \) $/x and do | 
| 345 | 545 | 100 |  |  |  | 2086 | { | 
| 346 | 298 |  |  |  |  | 704 | push @edges, $1-1; | 
| 347 | 298 |  |  |  |  | 449 | $set->{posInf} = 1; | 
| 348 | 298 |  |  |  |  | 914 | $last = 1; | 
| 349 | 298 |  |  |  |  | 433 | last RUN; | 
| 350 |  |  |  |  |  |  | }; | 
| 351 |  |  |  |  |  |  |  | 
| 352 |  |  |  |  |  |  | $run =~ /^ \( - \) $/x and do | 
| 353 | 247 | 100 |  |  |  | 760 | { | 
| 354 | 237 | 50 |  |  |  | 442 | croak "Set::IntSpan::_copy_run_list: Bad order 4: $runList\n" | 
| 355 |  |  |  |  |  |  | unless $first; | 
| 356 | 237 |  |  |  |  | 274 | $last = 1; | 
| 357 | 237 |  |  |  |  | 354 | $set->{negInf} = 1; | 
| 358 | 237 |  |  |  |  | 311 | $set->{posInf} = 1; | 
| 359 | 237 |  |  |  |  | 394 | last RUN; | 
| 360 |  |  |  |  |  |  | }; | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 10 |  |  |  |  | 1587 | croak "Set::IntSpan::_copy_run_list: Bad syntax: $runList\n"; | 
| 363 |  |  |  |  |  |  | } | 
| 364 |  |  |  |  |  |  |  | 
| 365 | 3063 |  |  |  |  | 6505 | $first = 0; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  |  | 
| 368 | 2142 |  |  |  |  | 6500 | $set->{edges} = [ @edges ]; | 
| 369 |  |  |  |  |  |  |  | 
| 370 | 2142 | 100 |  |  |  | 4649 | $set->_cleanup or | 
| 371 |  |  |  |  |  |  | croak "Set::IntSpan::_copy_run_list: Bad order 5: $runList\n"; | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | # check for overlapping runs | 
| 376 |  |  |  |  |  |  | # delete duplicate edges | 
| 377 |  |  |  |  |  |  | sub _cleanup | 
| 378 |  |  |  |  |  |  | { | 
| 379 | 2142 |  |  | 2142 |  | 2534 | my $set = shift; | 
| 380 | 2142 |  |  |  |  | 2961 | my $edges = $set->{edges}; | 
| 381 |  |  |  |  |  |  |  | 
| 382 | 2142 |  |  |  |  | 2313 | my $i=0; | 
| 383 | 2142 |  |  |  |  | 4831 | while ($i < $#$edges) | 
| 384 |  |  |  |  |  |  | { | 
| 385 | 3116 |  |  |  |  | 5259 | my $cmp = $$edges[$i] <=> $$edges[$i+1]; | 
| 386 |  |  |  |  |  |  | { | 
| 387 | 3116 | 100 |  |  |  | 3491 | $cmp == -1 and $i++                  , last; | 
|  | 3116 |  |  |  |  | 9219 |  | 
| 388 | 46 | 100 |  |  |  | 781 | $cmp ==  0 and splice(@$edges, $i, 2), last; | 
| 389 | 4 | 50 |  |  |  | 652 | $cmp ==  1 and return 0; | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  | } | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | 1 | 
| 394 | 2138 |  |  |  |  | 7740 | } | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  |  | 
| 397 |  |  |  |  |  |  | sub run_list | 
| 398 |  |  |  |  |  |  | { | 
| 399 | 1058 |  |  | 1058 | 1 | 5875 | my $set = shift; | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 1058 | 100 |  |  |  | 2084 | $set->empty and return ${$set->{empty_string}}; | 
|  | 240 |  |  |  |  | 848 |  | 
| 402 |  |  |  |  |  |  |  | 
| 403 | 818 |  |  |  |  | 1283 | my @edges = @{$set->{edges}}; | 
|  | 818 |  |  |  |  | 2093 |  | 
| 404 | 818 |  |  |  |  | 1071 | my @runs; | 
| 405 |  |  |  |  |  |  |  | 
| 406 | 818 | 100 |  |  |  | 1887 | $set->{negInf} and unshift @edges, '('; | 
| 407 | 818 | 100 |  |  |  | 2344 | $set->{posInf} and push    @edges, ')'; | 
| 408 |  |  |  |  |  |  |  | 
| 409 | 818 |  |  |  |  | 1898 | while(@edges) | 
| 410 |  |  |  |  |  |  | { | 
| 411 | 1239 |  |  |  |  | 2273 | my($lower, $upper) = splice @edges, 0, 2; | 
| 412 |  |  |  |  |  |  |  | 
| 413 | 1239 | 100 | 100 |  |  | 7276 | if ($lower ne '(' and $upper ne ')' and $lower+1==$upper) | 
|  |  |  | 100 |  |  |  |  | 
| 414 |  |  |  |  |  |  | { | 
| 415 | 305 |  |  |  |  | 1087 | push @runs, $upper; | 
| 416 |  |  |  |  |  |  | } | 
| 417 |  |  |  |  |  |  | else | 
| 418 |  |  |  |  |  |  | { | 
| 419 | 934 | 100 |  |  |  | 1960 | $lower ne '(' and $lower++; | 
| 420 | 934 |  |  |  |  | 3028 | push @runs, "$lower-$upper"; | 
| 421 |  |  |  |  |  |  | } | 
| 422 |  |  |  |  |  |  | } | 
| 423 |  |  |  |  |  |  |  | 
| 424 | 818 |  |  |  |  | 3608 | join(',', @runs) | 
| 425 |  |  |  |  |  |  | } | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | sub dump | 
| 428 |  |  |  |  |  |  | { | 
| 429 | 0 |  |  | 0 | 0 | 0 | my $set = shift; | 
| 430 | 0 | 0 |  |  |  | 0 | ($set->{negInf} ? '(' : '') . join ',', @{$set->{edges}} . ($set->{posInf} ? ')' : '') | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | sub elements | 
| 434 |  |  |  |  |  |  | { | 
| 435 | 58 |  |  | 58 | 1 | 874 | my $set = shift; | 
| 436 |  |  |  |  |  |  |  | 
| 437 | 58 | 100 | 100 |  |  | 2158 | ($set->{negInf} or $set->{posInf}) and | 
| 438 |  |  |  |  |  |  | croak "Set::IntSpan::elements: infinite set\n"; | 
| 439 |  |  |  |  |  |  |  | 
| 440 | 42 |  |  |  |  | 45 | my @elements; | 
| 441 | 42 |  |  |  |  | 41 | my @edges = @{$set->{edges}}; | 
|  | 42 |  |  |  |  | 121 |  | 
| 442 | 42 |  |  |  |  | 91 | while (@edges) | 
| 443 |  |  |  |  |  |  | { | 
| 444 | 40 |  |  |  |  | 81 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 445 | 40 |  |  |  |  | 304 | push @elements, $lower+1 .. $upper; | 
| 446 |  |  |  |  |  |  | } | 
| 447 |  |  |  |  |  |  |  | 
| 448 | 42 | 100 |  |  |  | 187 | wantarray ? @elements : \@elements | 
| 449 |  |  |  |  |  |  | } | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | sub sets | 
| 452 |  |  |  |  |  |  | { | 
| 453 | 23 |  |  | 23 | 1 | 71 | my $set   = shift; | 
| 454 | 23 |  |  |  |  | 28 | my @edges = @{$set->{edges}}; | 
|  | 23 |  |  |  |  | 62 |  | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 23 | 100 |  |  |  | 53 | unshift @edges, undef if $set->{negInf}; | 
| 457 | 23 | 100 |  |  |  | 50 | push    @edges, undef if $set->{posInf}; | 
| 458 |  |  |  |  |  |  |  | 
| 459 | 23 |  |  |  |  | 21 | my @sets; | 
| 460 | 23 |  |  |  |  | 42 | while (@edges) | 
| 461 |  |  |  |  |  |  | { | 
| 462 | 23 |  |  |  |  | 44 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 463 |  |  |  |  |  |  |  | 
| 464 | 23 | 100 |  |  |  | 59 | $lower = defined $lower ? $lower+1 : '('; | 
| 465 | 23 | 100 |  |  |  | 41 | $upper = defined $upper ? $upper   : ')'; | 
| 466 |  |  |  |  |  |  |  | 
| 467 | 23 |  |  |  |  | 82 | push @sets, Set::IntSpan->new("$lower-$upper"); | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | @sets | 
| 471 | 23 |  |  |  |  | 68 | } | 
| 472 |  |  |  |  |  |  |  | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | sub spans | 
| 475 |  |  |  |  |  |  | { | 
| 476 | 38 |  |  | 38 | 1 | 328 | my $set   = shift; | 
| 477 | 38 |  |  |  |  | 42 | my @edges = @{$set->{edges}}; | 
|  | 38 |  |  |  |  | 158 |  | 
| 478 |  |  |  |  |  |  |  | 
| 479 | 38 | 100 |  |  |  | 107 | unshift @edges, undef if $set->{negInf}; | 
| 480 | 38 | 100 |  |  |  | 82 | push    @edges, undef if $set->{posInf}; | 
| 481 |  |  |  |  |  |  |  | 
| 482 | 38 |  |  |  |  | 37 | my @spans; | 
| 483 | 38 |  |  |  |  | 76 | while (@edges) | 
| 484 |  |  |  |  |  |  | { | 
| 485 | 52 |  |  |  |  | 85 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 486 | 52 | 100 |  |  |  | 109 | $lower++ | 
| 487 |  |  |  |  |  |  | if defined $lower; | 
| 488 | 52 |  |  |  |  | 180 | push @spans, [$lower, $upper]; | 
| 489 |  |  |  |  |  |  | } | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | @spans | 
| 492 | 38 |  |  |  |  | 106 | } | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | sub _real_set		# converts a set specification into a set | 
| 496 |  |  |  |  |  |  | { | 
| 497 | 1046 |  |  | 1046 |  | 2198 | my($set, $set_spec) = @_; | 
| 498 |  |  |  |  |  |  |  | 
| 499 | 1046 | 100 | 100 |  |  | 6926 | (defined $set_spec and ref $set_spec and ref $set_spec ne 'ARRAY') ? | 
| 500 |  |  |  |  |  |  | $set_spec : | 
| 501 |  |  |  |  |  |  | $set->new($set_spec) | 
| 502 |  |  |  |  |  |  | } | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | sub U | 
| 505 |  |  |  |  |  |  | { | 
| 506 | 31 |  |  | 31 | 1 | 100 | my($a, $set_spec) = @_; | 
| 507 | 31 |  |  |  |  | 58 | my $s = $a->union($set_spec); | 
| 508 | 31 |  |  |  |  | 59 | $a->{negInf} = $s->{negInf}; | 
| 509 | 31 |  |  |  |  | 41 | $a->{posInf} = $s->{posInf}; | 
| 510 | 31 |  |  |  |  | 195 | $a->{edges } = $s->{edges }; | 
| 511 | 31 |  |  |  |  | 102 | $a | 
| 512 |  |  |  |  |  |  | } | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | sub union | 
| 515 |  |  |  |  |  |  | { | 
| 516 | 85 |  |  | 85 | 1 | 271 | my($a, $set_spec) = @_; | 
| 517 | 85 |  |  |  |  | 170 | my $b = $a->_real_set($set_spec); | 
| 518 | 85 |  |  |  |  | 169 | my $s = $a->new; | 
| 519 |  |  |  |  |  |  |  | 
| 520 | 85 |  | 100 |  |  | 351 | $s->{negInf} = $a->{negInf} || $b->{negInf}; | 
| 521 |  |  |  |  |  |  |  | 
| 522 | 85 |  |  |  |  | 131 | my $eA = $a->{edges}; | 
| 523 | 85 |  |  |  |  | 106 | my $eB = $b->{edges}; | 
| 524 | 85 |  |  |  |  | 117 | my $eS = $s->{edges}; | 
| 525 |  |  |  |  |  |  |  | 
| 526 | 85 |  |  |  |  | 103 | my $inA = $a->{negInf}; | 
| 527 | 85 |  |  |  |  | 104 | my $inB = $b->{negInf}; | 
| 528 |  |  |  |  |  |  |  | 
| 529 | 85 |  |  |  |  | 90 | my $iA = 0; | 
| 530 | 85 |  |  |  |  | 113 | my $iB = 0; | 
| 531 |  |  |  |  |  |  |  | 
| 532 | 85 |  | 100 |  |  | 352 | while ($iA<@$eA and $iB<@$eB) | 
| 533 |  |  |  |  |  |  | { | 
| 534 | 155 |  |  |  |  | 194 | my $xA = $$eA[$iA]; | 
| 535 | 155 |  |  |  |  | 168 | my $xB = $$eB[$iB]; | 
| 536 |  |  |  |  |  |  |  | 
| 537 | 155 | 100 |  |  |  | 308 | if ($xA < $xB) | 
|  |  | 100 |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | { | 
| 539 | 62 |  |  |  |  | 61 | $iA++; | 
| 540 | 62 |  |  |  |  | 73 | $inA = ! $inA; | 
| 541 | 62 | 100 |  |  |  | 261 | not $inB and push(@$eS, $xA); | 
| 542 |  |  |  |  |  |  | } | 
| 543 |  |  |  |  |  |  | elsif ($xB < $xA) | 
| 544 |  |  |  |  |  |  | { | 
| 545 | 58 |  |  |  |  | 60 | $iB++; | 
| 546 | 58 |  |  |  |  | 666 | $inB = ! $inB; | 
| 547 | 58 | 100 |  |  |  | 289 | not $inA and push(@$eS, $xB); | 
| 548 |  |  |  |  |  |  | } | 
| 549 |  |  |  |  |  |  | else | 
| 550 |  |  |  |  |  |  | { | 
| 551 | 35 |  |  |  |  | 35 | $iA++; | 
| 552 | 35 |  |  |  |  | 45 | $iB++; | 
| 553 | 35 |  |  |  |  | 41 | $inA = ! $inA; | 
| 554 | 35 |  |  |  |  | 40 | $inB = ! $inB; | 
| 555 | 35 | 100 |  |  |  | 153 | $inA == $inB and push(@$eS, $xA); | 
| 556 |  |  |  |  |  |  | } | 
| 557 |  |  |  |  |  |  | } | 
| 558 |  |  |  |  |  |  |  | 
| 559 | 85 | 100 | 100 |  |  | 524 | $iA < @$eA and ! $inB and push(@$eS, @$eA[$iA..$#$eA]); | 
| 560 | 85 | 100 | 100 |  |  | 342 | $iB < @$eB and ! $inA and push(@$eS, @$eB[$iB..$#$eB]); | 
| 561 |  |  |  |  |  |  |  | 
| 562 | 85 |  | 100 |  |  | 338 | $s->{posInf} = $a->{posInf} || $b->{posInf}; | 
| 563 | 85 |  |  |  |  | 454 | $s | 
| 564 |  |  |  |  |  |  | } | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  |  | 
| 567 |  |  |  |  |  |  | sub I | 
| 568 |  |  |  |  |  |  | { | 
| 569 | 31 |  |  | 31 | 1 | 94 | my($a, $set_spec) = @_; | 
| 570 | 31 |  |  |  |  | 55 | my $s = $a->intersect($set_spec); | 
| 571 | 31 |  |  |  |  | 48 | $a->{negInf} = $s->{negInf}; | 
| 572 | 31 |  |  |  |  | 36 | $a->{posInf} = $s->{posInf}; | 
| 573 | 31 |  |  |  |  | 44 | $a->{edges } = $s->{edges }; | 
| 574 | 31 |  |  |  |  | 86 | $a | 
| 575 |  |  |  |  |  |  | } | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | sub intersect | 
| 578 |  |  |  |  |  |  | { | 
| 579 | 67 |  |  | 67 | 1 | 209 | my($a, $set_spec) = @_; | 
| 580 | 67 |  |  |  |  | 128 | my $b = $a->_real_set($set_spec); | 
| 581 | 67 |  |  |  |  | 120 | my $s = $a->new; | 
| 582 |  |  |  |  |  |  |  | 
| 583 | 67 |  | 100 |  |  | 180 | $s->{negInf} = $a->{negInf} && $b->{negInf}; | 
| 584 |  |  |  |  |  |  |  | 
| 585 | 67 |  |  |  |  | 93 | my $eA = $a->{edges}; | 
| 586 | 67 |  |  |  |  | 82 | my $eB = $b->{edges}; | 
| 587 | 67 |  |  |  |  | 89 | my $eS = $s->{edges}; | 
| 588 |  |  |  |  |  |  |  | 
| 589 | 67 |  |  |  |  | 80 | my $inA = $a->{negInf}; | 
| 590 | 67 |  |  |  |  | 75 | my $inB = $b->{negInf}; | 
| 591 |  |  |  |  |  |  |  | 
| 592 | 67 |  |  |  |  | 68 | my $iA = 0; | 
| 593 | 67 |  |  |  |  | 71 | my $iB = 0; | 
| 594 |  |  |  |  |  |  |  | 
| 595 | 67 |  | 100 |  |  | 244 | while ($iA<@$eA and $iB<@$eB) | 
| 596 |  |  |  |  |  |  | { | 
| 597 | 124 |  |  |  |  | 138 | my $xA = $$eA[$iA]; | 
| 598 | 124 |  |  |  |  | 137 | my $xB = $$eB[$iB]; | 
| 599 |  |  |  |  |  |  |  | 
| 600 | 124 | 100 |  |  |  | 207 | if ($xA < $xB) | 
|  |  | 100 |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | { | 
| 602 | 46 |  |  |  |  | 49 | $iA++; | 
| 603 | 46 |  |  |  |  | 54 | $inA = ! $inA; | 
| 604 | 46 | 100 |  |  |  | 185 | $inB and push(@$eS, $xA); | 
| 605 |  |  |  |  |  |  | } | 
| 606 |  |  |  |  |  |  | elsif ($xB < $xA) | 
| 607 |  |  |  |  |  |  | { | 
| 608 | 43 |  |  |  |  | 42 | $iB++; | 
| 609 | 43 |  |  |  |  | 47 | $inB = ! $inB; | 
| 610 | 43 | 100 |  |  |  | 267 | $inA and push(@$eS, $xB); | 
| 611 |  |  |  |  |  |  | } | 
| 612 |  |  |  |  |  |  | else | 
| 613 |  |  |  |  |  |  | { | 
| 614 | 35 |  |  |  |  | 34 | $iA++; | 
| 615 | 35 |  |  |  |  | 34 | $iB++; | 
| 616 | 35 |  |  |  |  | 38 | $inA = ! $inA; | 
| 617 | 35 |  |  |  |  | 38 | $inB = ! $inB; | 
| 618 | 35 | 100 |  |  |  | 134 | $inA == $inB and push(@$eS, $xA); | 
| 619 |  |  |  |  |  |  | } | 
| 620 |  |  |  |  |  |  | } | 
| 621 |  |  |  |  |  |  |  | 
| 622 | 67 | 100 | 100 |  |  | 169 | $iA < @$eA and $inB and push(@$eS, @$eA[$iA..$#$eA]); | 
| 623 | 67 | 100 | 100 |  |  | 177 | $iB < @$eB and $inA and push(@$eS, @$eB[$iB..$#$eB]); | 
| 624 |  |  |  |  |  |  |  | 
| 625 | 67 |  | 100 |  |  | 171 | $s->{posInf} = $a->{posInf} && $b->{posInf}; | 
| 626 | 67 |  |  |  |  | 145 | $s | 
| 627 |  |  |  |  |  |  | } | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | sub D | 
| 631 |  |  |  |  |  |  | { | 
| 632 | 31 |  |  | 31 | 1 | 112 | my($a, $set_spec) = @_; | 
| 633 | 31 |  |  |  |  | 60 | my $s = $a->diff($set_spec); | 
| 634 | 31 |  |  |  |  | 49 | $a->{negInf} = $s->{negInf}; | 
| 635 | 31 |  |  |  |  | 76 | $a->{posInf} = $s->{posInf}; | 
| 636 | 31 |  |  |  |  | 49 | $a->{edges } = $s->{edges }; | 
| 637 | 31 |  |  |  |  | 98 | $a | 
| 638 |  |  |  |  |  |  | } | 
| 639 |  |  |  |  |  |  |  | 
| 640 |  |  |  |  |  |  | sub diff | 
| 641 |  |  |  |  |  |  | { | 
| 642 | 243 |  |  | 243 | 1 | 556 | my($a, $set_spec, $reverse) = @_; | 
| 643 | 243 |  |  |  |  | 455 | my $b = $a->_real_set($set_spec); | 
| 644 |  |  |  |  |  |  |  | 
| 645 | 243 |  |  |  |  | 510 | _reorder($a, $b, $reverse); | 
| 646 |  |  |  |  |  |  |  | 
| 647 | 243 |  |  |  |  | 442 | my $s = $a->new; | 
| 648 |  |  |  |  |  |  |  | 
| 649 | 243 |  | 100 |  |  | 798 | $s->{negInf} = $a->{negInf} && ! $b->{negInf}; | 
| 650 |  |  |  |  |  |  |  | 
| 651 | 243 |  |  |  |  | 340 | my $eA = $a->{edges}; | 
| 652 | 243 |  |  |  |  | 341 | my $eB = $b->{edges}; | 
| 653 | 243 |  |  |  |  | 309 | my $eS = $s->{edges}; | 
| 654 |  |  |  |  |  |  |  | 
| 655 | 243 |  |  |  |  | 323 | my $inA = $a->{negInf}; | 
| 656 | 243 |  |  |  |  | 339 | my $inB = $b->{negInf}; | 
| 657 |  |  |  |  |  |  |  | 
| 658 | 243 |  |  |  |  | 271 | my $iA = 0; | 
| 659 | 243 |  |  |  |  | 268 | my $iB = 0; | 
| 660 |  |  |  |  |  |  |  | 
| 661 | 243 |  | 100 |  |  | 1184 | while ($iA<@$eA and $iB<@$eB) | 
| 662 |  |  |  |  |  |  | { | 
| 663 | 325 |  |  |  |  | 469 | my $xA = $$eA[$iA]; | 
| 664 | 325 |  |  |  |  | 398 | my $xB = $$eB[$iB]; | 
| 665 |  |  |  |  |  |  |  | 
| 666 | 325 | 100 |  |  |  | 654 | if ($xA < $xB) | 
|  |  | 100 |  |  |  |  |  | 
| 667 |  |  |  |  |  |  | { | 
| 668 | 107 |  |  |  |  | 112 | $iA++; | 
| 669 | 107 |  |  |  |  | 142 | $inA = ! $inA; | 
| 670 | 107 | 100 |  |  |  | 494 | not $inB and push(@$eS, $xA); | 
| 671 |  |  |  |  |  |  | } | 
| 672 |  |  |  |  |  |  | elsif ($xB < $xA) | 
| 673 |  |  |  |  |  |  | { | 
| 674 | 107 |  |  |  |  | 131 | $iB++; | 
| 675 | 107 |  |  |  |  | 132 | $inB = ! $inB; | 
| 676 | 107 | 100 |  |  |  | 591 | $inA and push(@$eS, $xB); | 
| 677 |  |  |  |  |  |  | } | 
| 678 |  |  |  |  |  |  | else | 
| 679 |  |  |  |  |  |  | { | 
| 680 | 111 |  |  |  |  | 122 | $iA++; | 
| 681 | 111 |  |  |  |  | 119 | $iB++; | 
| 682 | 111 |  |  |  |  | 138 | $inA = ! $inA; | 
| 683 | 111 |  |  |  |  | 132 | $inB = ! $inB; | 
| 684 | 111 | 100 |  |  |  | 511 | $inA != $inB and push(@$eS, $xA); | 
| 685 |  |  |  |  |  |  | } | 
| 686 |  |  |  |  |  |  | } | 
| 687 |  |  |  |  |  |  |  | 
| 688 | 243 | 100 | 100 |  |  | 851 | $iA < @$eA and not $inB and push(@$eS, @$eA[$iA..$#$eA]); | 
| 689 | 243 | 100 | 100 |  |  | 784 | $iB < @$eB and     $inA and push(@$eS, @$eB[$iB..$#$eB]); | 
| 690 |  |  |  |  |  |  |  | 
| 691 | 243 |  | 100 |  |  | 690 | $s->{posInf} = $a->{posInf} && ! $b->{posInf}; | 
| 692 | 243 |  |  |  |  | 789 | $s | 
| 693 |  |  |  |  |  |  | } | 
| 694 |  |  |  |  |  |  |  | 
| 695 |  |  |  |  |  |  |  | 
| 696 |  |  |  |  |  |  | sub X | 
| 697 |  |  |  |  |  |  | { | 
| 698 | 31 |  |  | 31 | 1 | 103 | my($a, $set_spec) = @_; | 
| 699 | 31 |  |  |  |  | 56 | my $s = $a->xor($set_spec); | 
| 700 | 31 |  |  |  |  | 82 | $a->{negInf} = $s->{negInf}; | 
| 701 | 31 |  |  |  |  | 40 | $a->{posInf} = $s->{posInf}; | 
| 702 | 31 |  |  |  |  | 50 | $a->{edges } = $s->{edges }; | 
| 703 | 31 |  |  |  |  | 165 | $a | 
| 704 |  |  |  |  |  |  | } | 
| 705 |  |  |  |  |  |  |  | 
| 706 |  |  |  |  |  |  | sub xor | 
| 707 |  |  |  |  |  |  | { | 
| 708 | 67 |  |  | 67 | 1 | 188 | my($a, $set_spec) = @_; | 
| 709 | 67 |  |  |  |  | 123 | my $b = $a->_real_set($set_spec); | 
| 710 | 67 |  |  |  |  | 124 | my $s = $a->new; | 
| 711 |  |  |  |  |  |  |  | 
| 712 | 67 |  |  |  |  | 131 | $s->{negInf} = $a->{negInf} ^ $b->{negInf}; | 
| 713 |  |  |  |  |  |  |  | 
| 714 | 67 |  |  |  |  | 82 | my $eA = $a->{edges}; | 
| 715 | 67 |  |  |  |  | 83 | my $eB = $b->{edges}; | 
| 716 | 67 |  |  |  |  | 82 | my $eS = $s->{edges}; | 
| 717 |  |  |  |  |  |  |  | 
| 718 | 67 |  |  |  |  | 71 | my $iA = 0; | 
| 719 | 67 |  |  |  |  | 75 | my $iB = 0; | 
| 720 |  |  |  |  |  |  |  | 
| 721 | 67 |  | 100 |  |  | 264 | while ($iA<@$eA and $iB<@$eB) | 
| 722 |  |  |  |  |  |  | { | 
| 723 | 122 |  |  |  |  | 159 | my $xA = $$eA[$iA]; | 
| 724 | 122 |  |  |  |  | 155 | my $xB = $$eB[$iB]; | 
| 725 |  |  |  |  |  |  |  | 
| 726 | 122 | 100 |  |  |  | 4352 | if ($xA < $xB) | 
|  |  | 100 |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | { | 
| 728 | 45 |  |  |  |  | 51 | $iA++; | 
| 729 | 45 |  |  |  |  | 529 | push(@$eS, $xA); | 
| 730 |  |  |  |  |  |  | } | 
| 731 |  |  |  |  |  |  | elsif ($xB < $xA) | 
| 732 |  |  |  |  |  |  | { | 
| 733 | 43 |  |  |  |  | 45 | $iB++; | 
| 734 | 43 |  |  |  |  | 255 | push(@$eS, $xB); | 
| 735 |  |  |  |  |  |  | } | 
| 736 |  |  |  |  |  |  | else | 
| 737 |  |  |  |  |  |  | { | 
| 738 | 34 |  |  |  |  | 39 | $iA++; | 
| 739 | 34 |  |  |  |  | 117 | $iB++; | 
| 740 |  |  |  |  |  |  | } | 
| 741 |  |  |  |  |  |  | } | 
| 742 |  |  |  |  |  |  |  | 
| 743 | 67 | 100 |  |  |  | 165 | $iA < @$eA and push(@$eS, @$eA[$iA..$#$eA]); | 
| 744 | 67 | 100 |  |  |  | 223 | $iB < @$eB and push(@$eS, @$eB[$iB..$#$eB]); | 
| 745 |  |  |  |  |  |  |  | 
| 746 | 67 |  |  |  |  | 140 | $s->{posInf} = $a->{posInf} ^ $b->{posInf}; | 
| 747 | 67 |  |  |  |  | 140 | $s | 
| 748 |  |  |  |  |  |  | } | 
| 749 |  |  |  |  |  |  |  | 
| 750 |  |  |  |  |  |  |  | 
| 751 |  |  |  |  |  |  | sub complement | 
| 752 |  |  |  |  |  |  | { | 
| 753 | 13 |  |  | 13 | 1 | 64 | my $set = shift; | 
| 754 | 13 |  |  |  |  | 30 | $set->new($set)->C | 
| 755 |  |  |  |  |  |  | } | 
| 756 |  |  |  |  |  |  |  | 
| 757 |  |  |  |  |  |  | sub C | 
| 758 |  |  |  |  |  |  | { | 
| 759 | 23 |  |  | 23 | 1 | 48 | my $set = shift; | 
| 760 | 23 |  |  |  |  | 45 | $set->{negInf} = ! $set->{negInf}; | 
| 761 | 23 |  |  |  |  | 38 | $set->{posInf} = ! $set->{posInf}; | 
| 762 | 23 |  |  |  |  | 42 | $set | 
| 763 |  |  |  |  |  |  | } | 
| 764 |  |  |  |  |  |  |  | 
| 765 |  |  |  |  |  |  |  | 
| 766 |  |  |  |  |  |  | sub superset | 
| 767 |  |  |  |  |  |  | { | 
| 768 | 88 |  |  | 88 | 1 | 329 | my($a, $set_spec) = @_; | 
| 769 | 88 |  |  |  |  | 171 | my $b = $a->_real_set($set_spec); | 
| 770 |  |  |  |  |  |  |  | 
| 771 | 88 |  |  |  |  | 198 | $b->diff($a)->empty | 
| 772 |  |  |  |  |  |  | } | 
| 773 |  |  |  |  |  |  |  | 
| 774 |  |  |  |  |  |  |  | 
| 775 |  |  |  |  |  |  | sub subset | 
| 776 |  |  |  |  |  |  | { | 
| 777 | 88 |  |  | 88 | 1 | 346 | my($a, $b) = @_; | 
| 778 |  |  |  |  |  |  |  | 
| 779 | 88 |  |  |  |  | 210 | $a->diff($b)->empty | 
| 780 |  |  |  |  |  |  | } | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  |  | 
| 783 |  |  |  |  |  |  | sub equal | 
| 784 |  |  |  |  |  |  | { | 
| 785 | 349 |  |  | 349 | 1 | 6900 | my($a, $set_spec) = @_; | 
| 786 | 349 |  |  |  |  | 1157 | my $b = $a->_real_set($set_spec); | 
| 787 |  |  |  |  |  |  |  | 
| 788 | 349 | 100 |  |  |  | 1095 | $a->{negInf} == $b->{negInf} or return 0; | 
| 789 | 319 | 100 |  |  |  | 672 | $a->{posInf} == $b->{posInf} or return 0; | 
| 790 |  |  |  |  |  |  |  | 
| 791 | 305 |  |  |  |  | 795 | my $aEdge = $a->{edges}; | 
| 792 | 305 |  |  |  |  | 948 | my $bEdge = $b->{edges}; | 
| 793 | 305 | 100 |  |  |  | 610 | @$aEdge == @$bEdge or return 0; | 
| 794 |  |  |  |  |  |  |  | 
| 795 | 287 |  |  |  |  | 642 | for (my $i=0; $i<@$aEdge; $i++) | 
| 796 |  |  |  |  |  |  | { | 
| 797 | 564 | 100 |  |  |  | 1670 | $$aEdge[$i] == $$bEdge[$i] or return 0; | 
| 798 |  |  |  |  |  |  | } | 
| 799 |  |  |  |  |  |  |  | 
| 800 | 271 |  |  |  |  | 687 | 1 | 
| 801 |  |  |  |  |  |  | } | 
| 802 |  |  |  |  |  |  |  | 
| 803 |  |  |  |  |  |  |  | 
| 804 |  |  |  |  |  |  | sub equivalent | 
| 805 |  |  |  |  |  |  | { | 
| 806 | 81 |  |  | 81 | 1 | 290 | my($a, $set_spec) = @_; | 
| 807 | 81 |  |  |  |  | 163 | my $b = $a->_real_set($set_spec); | 
| 808 |  |  |  |  |  |  |  | 
| 809 | 81 |  |  |  |  | 701 | $a->cardinality == $b->cardinality | 
| 810 |  |  |  |  |  |  | } | 
| 811 |  |  |  |  |  |  |  | 
| 812 |  |  |  |  |  |  |  | 
| 813 |  |  |  |  |  |  | sub cardinality | 
| 814 |  |  |  |  |  |  | { | 
| 815 | 198 |  |  | 198 | 1 | 246 | my $set = shift; | 
| 816 |  |  |  |  |  |  |  | 
| 817 | 198 | 100 | 100 |  |  | 864 | ($set->{negInf} or $set->{posInf}) and return -1; | 
| 818 |  |  |  |  |  |  |  | 
| 819 | 138 |  |  |  |  | 196 | my $cardinality = 0; | 
| 820 | 138 |  |  |  |  | 148 | my @edges = @{$set->{edges}}; | 
|  | 138 |  |  |  |  | 358 |  | 
| 821 | 138 |  |  |  |  | 369 | while (@edges) | 
| 822 |  |  |  |  |  |  | { | 
| 823 | 157 |  |  |  |  | 196 | my $lower = shift @edges; | 
| 824 | 157 |  |  |  |  | 194 | my $upper = shift @edges; | 
| 825 | 157 |  |  |  |  | 384 | $cardinality += $upper - $lower; | 
| 826 |  |  |  |  |  |  | } | 
| 827 |  |  |  |  |  |  |  | 
| 828 |  |  |  |  |  |  | $cardinality | 
| 829 | 138 |  |  |  |  | 353 | } | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | *size = \&cardinality; | 
| 832 |  |  |  |  |  |  |  | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  | sub empty | 
| 835 |  |  |  |  |  |  | { | 
| 836 | 1302 |  |  | 1302 | 1 | 1428 | my $set = shift; | 
| 837 |  |  |  |  |  |  |  | 
| 838 | 1302 |  | 66 |  |  | 3890 | not $set->{negInf} and not @{$set->{edges}} and not $set->{posInf} | 
| 839 |  |  |  |  |  |  | } | 
| 840 |  |  |  |  |  |  |  | 
| 841 |  |  |  |  |  |  |  | 
| 842 |  |  |  |  |  |  | sub finite | 
| 843 |  |  |  |  |  |  | { | 
| 844 | 27 |  |  | 27 | 1 | 97 | my $set = shift; | 
| 845 |  |  |  |  |  |  |  | 
| 846 | 27 |  | 100 |  |  | 131 | not $set->{negInf} and not $set->{posInf} | 
| 847 |  |  |  |  |  |  | } | 
| 848 |  |  |  |  |  |  |  | 
| 849 |  |  |  |  |  |  |  | 
| 850 | 162 |  |  | 162 | 1 | 1093 | sub neg_inf { shift->{negInf} } | 
| 851 | 242 |  |  | 242 | 1 | 1510 | sub pos_inf { shift->{posInf} } | 
| 852 |  |  |  |  |  |  |  | 
| 853 |  |  |  |  |  |  |  | 
| 854 |  |  |  |  |  |  | sub infinite | 
| 855 |  |  |  |  |  |  | { | 
| 856 | 9 |  |  | 9 | 1 | 35 | my $set = shift; | 
| 857 |  |  |  |  |  |  |  | 
| 858 | 9 | 100 |  |  |  | 40 | $set->{negInf} or $set->{posInf} | 
| 859 |  |  |  |  |  |  | } | 
| 860 |  |  |  |  |  |  |  | 
| 861 |  |  |  |  |  |  |  | 
| 862 |  |  |  |  |  |  | sub universal | 
| 863 |  |  |  |  |  |  | { | 
| 864 | 9 |  |  | 9 | 1 | 40 | my $set = shift; | 
| 865 |  |  |  |  |  |  |  | 
| 866 | 9 | 100 | 100 |  |  | 613 | $set->{negInf} and not @{$set->{edges}} and $set->{posInf} | 
|  | 2 |  |  |  |  | 15 |  | 
| 867 |  |  |  |  |  |  | } | 
| 868 |  |  |  |  |  |  |  | 
| 869 |  |  |  |  |  |  |  | 
| 870 |  |  |  |  |  |  | sub member | 
| 871 |  |  |  |  |  |  | { | 
| 872 | 97 |  |  | 97 | 1 | 371 | my($set, $n) = @_; | 
| 873 |  |  |  |  |  |  |  | 
| 874 | 97 |  |  |  |  | 203 | my $i = _bsearch($set->{edges}, $n); | 
| 875 |  |  |  |  |  |  |  | 
| 876 | 97 |  | 100 |  |  | 541 | $set->{negInf} xor $i & 1 | 
| 877 |  |  |  |  |  |  | } | 
| 878 |  |  |  |  |  |  |  | 
| 879 | 20 |  |  | 20 |  | 136335 | use constant INSERT => 0; | 
|  | 20 |  |  |  |  | 50 |  | 
|  | 20 |  |  |  |  | 11856 |  | 
| 880 | 20 |  |  | 20 |  | 123 | use constant REMOVE => 1; | 
|  | 20 |  |  |  |  | 39 |  | 
|  | 20 |  |  |  |  | 104905 |  | 
| 881 |  |  |  |  |  |  |  | 
| 882 | 461 |  |  | 461 | 1 | 1426 | sub insert { _indel(@_, INSERT); } | 
| 883 | 49 |  |  | 49 | 1 | 247 | sub remove { _indel(@_, REMOVE); } | 
| 884 |  |  |  |  |  |  |  | 
| 885 |  |  |  |  |  |  | sub _indel # INsertion/DELetion | 
| 886 |  |  |  |  |  |  | { | 
| 887 | 510 |  |  | 510 |  | 708 | my($set, $n, $indel) = @_; | 
| 888 | 510 | 50 |  |  |  | 1170 | defined $n or return; | 
| 889 |  |  |  |  |  |  |  | 
| 890 | 510 |  |  |  |  | 739 | my $edge = $set->{edges}; | 
| 891 | 510 |  |  |  |  | 1067 | my $i    = _bsearch($edge, $n); | 
| 892 |  |  |  |  |  |  |  | 
| 893 | 510 | 100 | 100 |  |  | 4238 | return if $set->{negInf} xor $i & 1 xor $indel; | 
|  |  |  | 100 |  |  |  |  | 
| 894 |  |  |  |  |  |  |  | 
| 895 | 423 |  | 100 |  |  | 1422 | my $lGap = $i==0      || $edge->[$i-1] < $n-1; | 
| 896 | 423 |  | 100 |  |  | 1117 | my $rGap = $i==@$edge || $n            < $edge->[$i]; | 
| 897 |  |  |  |  |  |  |  | 
| 898 | 423 | 100 | 100 |  |  | 2198 | if    (    $lGap and     $rGap) { splice @$edge, $i, 0, $n-1, $n } | 
|  | 81 | 100 | 100 |  |  | 497 |  | 
|  |  | 100 | 66 |  |  |  |  | 
| 899 | 284 |  |  |  |  | 1073 | elsif (not $lGap and     $rGap) { $edge->[$i-1]++                } | 
| 900 | 55 |  |  |  |  | 253 | elsif (    $lGap and not $rGap) { $edge->[$i  ]--                } | 
| 901 | 3 |  |  |  |  | 21 | else                            { splice @$edge, $i-1, 2         } | 
| 902 |  |  |  |  |  |  | } | 
| 903 |  |  |  |  |  |  |  | 
| 904 |  |  |  |  |  |  | # Returns the index of the first edge that satisifies target <= edge. | 
| 905 |  |  |  |  |  |  | # Returns $#$edges+1 if target > the last edge. | 
| 906 |  |  |  |  |  |  | # Returns 0 if edges is empty. | 
| 907 |  |  |  |  |  |  | sub _bsearch | 
| 908 |  |  |  |  |  |  | { | 
| 909 | 756 |  |  | 756 |  | 2259 | my($edges, $target) = @_; | 
| 910 |  |  |  |  |  |  |  | 
| 911 | 756 | 100 |  |  |  | 1526 | @$edges or return 0; | 
| 912 |  |  |  |  |  |  |  | 
| 913 | 681 |  |  |  |  | 721 | my $lower = 0; | 
| 914 | 681 |  |  |  |  | 854 | my $upper = $#$edges; | 
| 915 |  |  |  |  |  |  |  | 
| 916 | 681 |  |  |  |  | 1694 | while ($lower+1 < $upper) | 
| 917 |  |  |  |  |  |  | { | 
| 918 | 727 |  |  |  |  | 1133 | my $mid = int(($lower + $upper) / 2); | 
| 919 |  |  |  |  |  |  |  | 
| 920 | 727 | 100 |  |  |  | 1919 | if ($target <= $edges->[$mid]) | 
| 921 |  |  |  |  |  |  | { | 
| 922 | 264 |  |  |  |  | 586 | $upper = $mid; | 
| 923 |  |  |  |  |  |  | } | 
| 924 |  |  |  |  |  |  | else | 
| 925 |  |  |  |  |  |  | { | 
| 926 | 463 |  |  |  |  | 1172 | $lower = $mid+1; | 
| 927 |  |  |  |  |  |  | } | 
| 928 |  |  |  |  |  |  | } | 
| 929 |  |  |  |  |  |  |  | 
| 930 | 681 | 100 |  |  |  | 1712 | $target <= $edges->[$lower] and return $lower; | 
| 931 | 493 | 100 |  |  |  | 1058 | $target <= $edges->[$upper] and return $upper; | 
| 932 | 358 |  |  |  |  | 645 | $upper + 1 | 
| 933 |  |  |  |  |  |  | } | 
| 934 |  |  |  |  |  |  |  | 
| 935 |  |  |  |  |  |  | sub span_ord | 
| 936 |  |  |  |  |  |  | { | 
| 937 | 24 |  |  | 24 | 1 | 87 | my($set, $n) = @_; | 
| 938 |  |  |  |  |  |  |  | 
| 939 | 24 |  |  |  |  | 49 | my $i = _bsearch($set->{edges}, $n); | 
| 940 | 24 | 100 | 100 |  |  | 144 | ($set->{negInf} xor $i & 1) ? $i >> 1 : undef | 
| 941 |  |  |  |  |  |  | } | 
| 942 |  |  |  |  |  |  |  | 
| 943 |  |  |  |  |  |  | sub min | 
| 944 |  |  |  |  |  |  | { | 
| 945 | 26 |  |  | 26 | 1 | 56 | my $set = shift; | 
| 946 |  |  |  |  |  |  |  | 
| 947 | 26 | 100 |  |  |  | 50 | $set->empty   and return undef; | 
| 948 | 23 | 100 |  |  |  | 156 | $set->neg_inf and return undef; | 
| 949 | 19 |  |  |  |  | 52 | $set->{edges}->[0]+1 | 
| 950 |  |  |  |  |  |  | } | 
| 951 |  |  |  |  |  |  |  | 
| 952 |  |  |  |  |  |  |  | 
| 953 |  |  |  |  |  |  | sub max | 
| 954 |  |  |  |  |  |  | { | 
| 955 | 26 |  |  | 26 | 1 | 52 | my $set = shift; | 
| 956 |  |  |  |  |  |  |  | 
| 957 | 26 | 100 |  |  |  | 45 | $set->empty   and return undef; | 
| 958 | 23 | 100 |  |  |  | 132 | $set->pos_inf and return undef; | 
| 959 | 19 |  |  |  |  | 56 | $set->{edges}->[-1] | 
| 960 |  |  |  |  |  |  | } | 
| 961 |  |  |  |  |  |  |  | 
| 962 |  |  |  |  |  |  | sub cover | 
| 963 |  |  |  |  |  |  | { | 
| 964 | 13 |  |  | 13 | 1 | 185 | my $set    = shift; | 
| 965 | 13 |  |  |  |  | 20 | my $cover  = $set->new(); | 
| 966 | 13 |  |  |  |  | 19 | my $edges  = $set->{edges}; | 
| 967 | 13 |  |  |  |  | 19 | my $negInf = $set->{negInf}; | 
| 968 | 13 |  |  |  |  | 16 | my $posInf = $set->{posInf}; | 
| 969 |  |  |  |  |  |  |  | 
| 970 | 13 | 100 | 100 |  |  | 522 | if ($negInf and $posInf) | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 971 |  |  |  |  |  |  | { | 
| 972 | 2 |  |  |  |  | 3 | $cover->{negInf}   = 1; | 
| 973 | 2 |  |  |  |  | 4 | $cover->{posInf}   = 1; | 
| 974 |  |  |  |  |  |  | } | 
| 975 |  |  |  |  |  |  | elsif ($negInf and not $posInf) | 
| 976 |  |  |  |  |  |  | { | 
| 977 | 2 |  |  |  |  | 4 | $cover->{negInf}   = 1; | 
| 978 | 2 |  |  |  |  | 6 | $cover->{edges}[0] = $set->{edges}[-1]; | 
| 979 |  |  |  |  |  |  | } | 
| 980 |  |  |  |  |  |  | elsif (not $negInf and $posInf) | 
| 981 |  |  |  |  |  |  | { | 
| 982 | 2 |  |  |  |  | 6 | $cover->{edges}[0] = $set->{edges}[0]; | 
| 983 | 2 |  |  |  |  | 5 | $cover->{posInf}   = 1; | 
| 984 |  |  |  |  |  |  | } | 
| 985 |  |  |  |  |  |  | elsif (@$edges) | 
| 986 |  |  |  |  |  |  | { | 
| 987 | 5 |  |  |  |  | 10 | $cover->{edges}[0] = $set->{edges}[ 0]; | 
| 988 | 5 |  |  |  |  | 10 | $cover->{edges}[1] = $set->{edges}[-1]; | 
| 989 |  |  |  |  |  |  | } | 
| 990 |  |  |  |  |  |  |  | 
| 991 |  |  |  |  |  |  | $cover | 
| 992 | 13 |  |  |  |  | 28 | } | 
| 993 |  |  |  |  |  |  |  | 
| 994 |  |  |  |  |  |  | *extent = \&cover; | 
| 995 |  |  |  |  |  |  |  | 
| 996 |  |  |  |  |  |  |  | 
| 997 |  |  |  |  |  |  | sub holes | 
| 998 |  |  |  |  |  |  | { | 
| 999 | 13 |  |  | 13 | 1 | 32 | my $set    = shift; | 
| 1000 | 13 |  |  |  |  | 18 | my $holes  = $set->new($set); | 
| 1001 | 13 |  |  |  |  | 16 | my $edges  = $holes->{edges}; | 
| 1002 | 13 |  |  |  |  | 15 | my $negInf = $holes->{negInf}; | 
| 1003 | 13 |  |  |  |  | 13 | my $posInf = $holes->{posInf}; | 
| 1004 |  |  |  |  |  |  |  | 
| 1005 | 13 | 100 | 100 |  |  | 82 | if ($negInf and $posInf) | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  | { | 
| 1007 | 2 |  |  |  |  | 3 | $holes->{negInf}   = 0; | 
| 1008 | 2 |  |  |  |  | 3 | $holes->{posInf}   = 0; | 
| 1009 |  |  |  |  |  |  | } | 
| 1010 |  |  |  |  |  |  | elsif ($negInf and not $posInf) | 
| 1011 |  |  |  |  |  |  | { | 
| 1012 | 2 |  |  |  |  | 3 | $holes->{negInf}   = 0; | 
| 1013 | 2 |  |  |  |  | 3 | pop   @$edges; | 
| 1014 |  |  |  |  |  |  | } | 
| 1015 |  |  |  |  |  |  | elsif (not $negInf and $posInf) | 
| 1016 |  |  |  |  |  |  | { | 
| 1017 | 2 |  |  |  |  | 4 | shift @$edges; | 
| 1018 | 2 |  |  |  |  | 4 | $holes->{posInf}   = 0; | 
| 1019 |  |  |  |  |  |  | } | 
| 1020 |  |  |  |  |  |  | elsif (@$edges) | 
| 1021 |  |  |  |  |  |  | { | 
| 1022 | 5 |  |  |  |  | 6 | shift @$edges; | 
| 1023 | 5 |  |  |  |  | 6 | pop   @$edges; | 
| 1024 |  |  |  |  |  |  | } | 
| 1025 |  |  |  |  |  |  |  | 
| 1026 |  |  |  |  |  |  | $holes | 
| 1027 | 13 |  |  |  |  | 24 | } | 
| 1028 |  |  |  |  |  |  |  | 
| 1029 |  |  |  |  |  |  | sub inset | 
| 1030 |  |  |  |  |  |  | { | 
| 1031 | 37 |  |  | 37 | 1 | 123 | my($set, $n) = @_; | 
| 1032 | 37 |  |  |  |  | 47 | my $edges = $set->{edges}; | 
| 1033 | 37 |  |  |  |  | 93 | my @edges = @$edges; | 
| 1034 |  |  |  |  |  |  |  | 
| 1035 | 37 |  |  |  |  | 53 | my $inset = $set->new(); | 
| 1036 | 37 |  |  |  |  | 56 | $inset->{negInf} = $set->{negInf}; | 
| 1037 | 37 |  |  |  |  | 54 | $inset->{posInf} = $set->{posInf}; | 
| 1038 |  |  |  |  |  |  |  | 
| 1039 | 37 |  |  |  |  | 35 | my @inset; | 
| 1040 | 37 |  |  |  |  | 41 | my $nAbs = abs $n; | 
| 1041 |  |  |  |  |  |  |  | 
| 1042 | 37 | 100 | 100 |  |  | 251 | if (@edges and ($inset->{negInf} xor $n < 0)) | 
|  |  |  | 100 |  |  |  |  | 
| 1043 |  |  |  |  |  |  | { | 
| 1044 | 13 |  |  |  |  | 19 | my $edge = shift @edges; | 
| 1045 | 13 |  |  |  |  | 27 | push @inset, $edge - $nAbs; | 
| 1046 |  |  |  |  |  |  | } | 
| 1047 |  |  |  |  |  |  |  | 
| 1048 | 37 |  |  |  |  | 88 | while (@edges > 1) | 
| 1049 |  |  |  |  |  |  | { | 
| 1050 | 79 |  |  |  |  | 151 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 1051 | 79 |  |  |  |  | 137 | $lower += $nAbs; | 
| 1052 | 79 |  |  |  |  | 72 | $upper -= $nAbs; | 
| 1053 |  |  |  |  |  |  |  | 
| 1054 | 79 | 100 |  |  |  | 225 | push @inset, $lower, $upper | 
| 1055 |  |  |  |  |  |  | if $lower < $upper; | 
| 1056 |  |  |  |  |  |  | } | 
| 1057 |  |  |  |  |  |  |  | 
| 1058 | 37 | 100 |  |  |  | 64 | if (@edges) | 
| 1059 |  |  |  |  |  |  | { | 
| 1060 | 13 |  |  |  |  | 19 | my $edge = shift @edges; | 
| 1061 | 13 |  |  |  |  | 24 | push @inset, $edge + $nAbs; | 
| 1062 |  |  |  |  |  |  | } | 
| 1063 |  |  |  |  |  |  |  | 
| 1064 |  |  |  |  |  |  |  | 
| 1065 | 37 |  |  |  |  | 60 | $inset->{edges} = \@inset; | 
| 1066 | 37 |  |  |  |  | 135 | $inset | 
| 1067 |  |  |  |  |  |  | } | 
| 1068 |  |  |  |  |  |  |  | 
| 1069 |  |  |  |  |  |  | *trim = \&inset; | 
| 1070 |  |  |  |  |  |  |  | 
| 1071 |  |  |  |  |  |  | sub pad | 
| 1072 |  |  |  |  |  |  | { | 
| 1073 | 1 |  |  | 1 | 1 | 3 | my($set, $n) = @_; | 
| 1074 | 1 |  |  |  |  | 4 | $set->inset(-$n) | 
| 1075 |  |  |  |  |  |  | } | 
| 1076 |  |  |  |  |  |  |  | 
| 1077 |  |  |  |  |  |  |  | 
| 1078 |  |  |  |  |  |  | sub grep_set(&$) | 
| 1079 |  |  |  |  |  |  | { | 
| 1080 | 45 |  |  | 45 | 1 | 266 | my($block, $set) = @_; | 
| 1081 |  |  |  |  |  |  |  | 
| 1082 | 45 | 100 | 100 |  |  | 578 | return undef if $set->{negInf} or $set->{posInf}; | 
| 1083 |  |  |  |  |  |  |  | 
| 1084 | 30 |  |  |  |  | 34 | my @edges     = @{$set->{edges}}; | 
|  | 30 |  |  |  |  | 91 |  | 
| 1085 | 30 |  |  |  |  | 44 | my @sub_edges = (); | 
| 1086 |  |  |  |  |  |  |  | 
| 1087 | 30 |  |  |  |  | 66 | while (@edges) | 
| 1088 |  |  |  |  |  |  | { | 
| 1089 | 35 |  |  |  |  | 310 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 1090 |  |  |  |  |  |  |  | 
| 1091 | 35 |  |  |  |  | 695 | for (my $i=$lower+1; $i<=$upper; $i++) | 
| 1092 |  |  |  |  |  |  | { | 
| 1093 | 150 |  |  |  |  | 3411 | local $_ = $i; | 
| 1094 | 150 | 100 |  |  |  | 467 | &$block() or next; | 
| 1095 |  |  |  |  |  |  |  | 
| 1096 | 60 | 100 | 100 |  |  | 3181 | if (@sub_edges and $sub_edges[-1] == $i-1) | 
| 1097 |  |  |  |  |  |  | { | 
| 1098 | 29 |  |  |  |  | 87 | $sub_edges[-1] = $i; | 
| 1099 |  |  |  |  |  |  | } | 
| 1100 |  |  |  |  |  |  | else | 
| 1101 |  |  |  |  |  |  | { | 
| 1102 | 31 |  |  |  |  | 127 | push @sub_edges, $i-1, $i; | 
| 1103 |  |  |  |  |  |  | } | 
| 1104 |  |  |  |  |  |  | } | 
| 1105 |  |  |  |  |  |  | } | 
| 1106 |  |  |  |  |  |  |  | 
| 1107 | 30 |  |  |  |  | 883 | my $sub_set = $set->new; | 
| 1108 | 30 |  |  |  |  | 81 | $sub_set->{edges} = \@sub_edges; | 
| 1109 | 30 |  |  |  |  | 109 | $sub_set | 
| 1110 |  |  |  |  |  |  | } | 
| 1111 |  |  |  |  |  |  |  | 
| 1112 |  |  |  |  |  |  |  | 
| 1113 |  |  |  |  |  |  | sub map_set(&$) | 
| 1114 |  |  |  |  |  |  | { | 
| 1115 | 63 |  |  | 63 | 1 | 368 | my($block, $set) = @_; | 
| 1116 |  |  |  |  |  |  |  | 
| 1117 | 63 | 100 | 100 |  |  | 381 | return undef if $set->{negInf} or $set->{posInf}; | 
| 1118 |  |  |  |  |  |  |  | 
| 1119 | 42 |  |  |  |  | 84 | my $map_set = $set->new; | 
| 1120 |  |  |  |  |  |  |  | 
| 1121 | 42 |  |  |  |  | 52 | my @edges = @{$set->{edges}}; | 
|  | 42 |  |  |  |  | 214 |  | 
| 1122 | 42 |  |  |  |  | 235 | while (@edges) | 
| 1123 |  |  |  |  |  |  | { | 
| 1124 | 49 |  |  |  |  | 179 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 1125 |  |  |  |  |  |  |  | 
| 1126 | 49 |  |  |  |  | 225 | my $domain; | 
| 1127 | 49 |  |  |  |  | 190 | for ($domain=$lower+1; $domain<=$upper; $domain++) | 
| 1128 |  |  |  |  |  |  | { | 
| 1129 | 210 |  |  |  |  | 824 | local $_ = $domain; | 
| 1130 |  |  |  |  |  |  |  | 
| 1131 | 210 |  |  |  |  | 215 | my $range; | 
| 1132 | 210 |  |  |  |  | 479 | for $range (&$block()) | 
| 1133 |  |  |  |  |  |  | { | 
| 1134 | 210 |  |  |  |  | 9988 | $map_set->insert($range); | 
| 1135 |  |  |  |  |  |  | } | 
| 1136 |  |  |  |  |  |  | } | 
| 1137 |  |  |  |  |  |  | } | 
| 1138 |  |  |  |  |  |  |  | 
| 1139 |  |  |  |  |  |  | $map_set | 
| 1140 | 42 |  |  |  |  | 330 | } | 
| 1141 |  |  |  |  |  |  |  | 
| 1142 |  |  |  |  |  |  |  | 
| 1143 |  |  |  |  |  |  | sub grep_spans(&$) | 
| 1144 |  |  |  |  |  |  | { | 
| 1145 | 40 |  |  | 40 | 1 | 216 | my($block, $set) = @_; | 
| 1146 |  |  |  |  |  |  |  | 
| 1147 | 40 |  |  |  |  | 42 | my @edges     = @{$set->{edges}}; | 
|  | 40 |  |  |  |  | 102 |  | 
| 1148 | 40 |  |  |  |  | 79 | my $sub_set   = $set->new; | 
| 1149 | 40 |  |  |  |  | 50 | my @sub_edges = (); | 
| 1150 |  |  |  |  |  |  |  | 
| 1151 | 40 | 100 | 100 |  |  | 153 | if ($set->{negInf} and $set->{posInf}) | 
|  |  | 100 |  |  |  |  |  | 
| 1152 |  |  |  |  |  |  | { | 
| 1153 | 4 |  |  |  |  | 7 | local $_ = [ undef, undef ]; | 
| 1154 | 4 | 100 |  |  |  | 9 | if (&$block()) | 
| 1155 |  |  |  |  |  |  | { | 
| 1156 | 2 |  |  |  |  | 110 | $sub_set->{negInf} = 1; | 
| 1157 | 2 |  |  |  |  | 5 | $sub_set->{posInf} = 1; | 
| 1158 |  |  |  |  |  |  | } | 
| 1159 |  |  |  |  |  |  | } | 
| 1160 |  |  |  |  |  |  | elsif ($set->{negInf}) | 
| 1161 |  |  |  |  |  |  | { | 
| 1162 | 4 |  |  |  |  | 7 | my $upper = shift @edges; | 
| 1163 | 4 |  |  |  |  | 10 | local $_ = [ undef, $upper ]; | 
| 1164 | 4 | 100 |  |  |  | 8 | if (&$block()) | 
| 1165 |  |  |  |  |  |  | { | 
| 1166 | 2 |  |  |  |  | 83 | $sub_set->{negInf} = 1; | 
| 1167 | 2 |  |  |  |  | 7 | push @sub_edges, $upper; | 
| 1168 |  |  |  |  |  |  | } | 
| 1169 |  |  |  |  |  |  | } | 
| 1170 |  |  |  |  |  |  |  | 
| 1171 | 40 |  |  |  |  | 292 | while (@edges > 1) | 
| 1172 |  |  |  |  |  |  | { | 
| 1173 | 40 |  |  |  |  | 790 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 1174 | 40 |  |  |  |  | 98 | local $_ = [ $lower+1, $upper ]; | 
| 1175 | 40 | 100 |  |  |  | 83 | &$block() and push @sub_edges, $lower, $upper; | 
| 1176 |  |  |  |  |  |  | } | 
| 1177 |  |  |  |  |  |  |  | 
| 1178 | 40 | 100 |  |  |  | 1159 | if (@edges) | 
| 1179 |  |  |  |  |  |  | { | 
| 1180 | 8 |  |  |  |  | 11 | my $lower = shift @edges; | 
| 1181 | 8 |  |  |  |  | 16 | local $_ = [ $lower+1, undef ]; | 
| 1182 | 8 | 100 |  |  |  | 19 | if (&$block()) | 
| 1183 |  |  |  |  |  |  | { | 
| 1184 | 4 |  |  |  |  | 153 | $sub_set->{posInf} = 1; | 
| 1185 | 4 |  |  |  |  | 11 | push @sub_edges, $lower; | 
| 1186 |  |  |  |  |  |  | } | 
| 1187 |  |  |  |  |  |  | } | 
| 1188 |  |  |  |  |  |  |  | 
| 1189 | 40 |  |  |  |  | 234 | $sub_set->{edges} = \@sub_edges; | 
| 1190 | 40 |  |  |  |  | 108 | $sub_set | 
| 1191 |  |  |  |  |  |  | } | 
| 1192 |  |  |  |  |  |  |  | 
| 1193 |  |  |  |  |  |  | sub map_spans(&$) | 
| 1194 |  |  |  |  |  |  | { | 
| 1195 | 60 |  |  | 60 | 1 | 324 | my($block, $set) = @_; | 
| 1196 |  |  |  |  |  |  |  | 
| 1197 | 60 |  |  |  |  | 59 | my @edges = @{$set->{edges}}; | 
|  | 60 |  |  |  |  | 154 |  | 
| 1198 | 60 |  |  |  |  | 64 | my @spans; | 
| 1199 |  |  |  |  |  |  |  | 
| 1200 | 60 | 100 | 100 |  |  | 233 | if ($set->{negInf} and $set->{posInf}) | 
|  |  | 100 |  |  |  |  |  | 
| 1201 |  |  |  |  |  |  | { | 
| 1202 | 6 |  |  |  |  | 13 | local $_ = [ undef, undef ]; | 
| 1203 | 6 |  |  |  |  | 15 | push @spans, &$block(); | 
| 1204 |  |  |  |  |  |  | } | 
| 1205 |  |  |  |  |  |  | elsif ($set->{negInf}) | 
| 1206 |  |  |  |  |  |  | { | 
| 1207 | 6 |  |  |  |  | 10 | my $upper = shift @edges; | 
| 1208 | 6 |  |  |  |  | 13 | local $_ = [ undef, $upper ]; | 
| 1209 | 6 |  |  |  |  | 14 | push @spans, &$block(); | 
| 1210 |  |  |  |  |  |  | } | 
| 1211 |  |  |  |  |  |  |  | 
| 1212 | 60 |  |  |  |  | 764 | while (@edges > 1) | 
| 1213 |  |  |  |  |  |  | { | 
| 1214 | 60 |  |  |  |  | 1109 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 1215 | 60 |  |  |  |  | 132 | local $_ = [ $lower+1, $upper ]; | 
| 1216 | 60 |  |  |  |  | 113 | push @spans, &$block(); | 
| 1217 |  |  |  |  |  |  | } | 
| 1218 |  |  |  |  |  |  |  | 
| 1219 | 60 | 100 |  |  |  | 1694 | if (@edges) | 
| 1220 |  |  |  |  |  |  | { | 
| 1221 | 12 |  |  |  |  | 17 | my $lower = shift @edges; | 
| 1222 | 12 |  |  |  |  | 27 | local $_ = [ $lower+1, undef ]; | 
| 1223 | 12 |  |  |  |  | 26 | push @spans, &$block(); | 
| 1224 |  |  |  |  |  |  | } | 
| 1225 |  |  |  |  |  |  |  | 
| 1226 | 60 |  |  |  |  | 655 | $set->new->_insert_spans(\@spans) | 
| 1227 |  |  |  |  |  |  | } | 
| 1228 |  |  |  |  |  |  |  | 
| 1229 |  |  |  |  |  |  |  | 
| 1230 |  |  |  |  |  |  | sub first($) | 
| 1231 |  |  |  |  |  |  | { | 
| 1232 | 17 |  |  | 17 | 1 | 64 | my $set   = shift; | 
| 1233 |  |  |  |  |  |  |  | 
| 1234 | 17 |  |  |  |  | 35 | $set->{iterator} = $set->min; | 
| 1235 | 17 |  |  |  |  | 42 | $set->{run}[0]   = 0; | 
| 1236 | 17 | 100 |  |  |  | 22 | $set->{run}[1]   = $#{$set->{edges}} ? 1 : undef; | 
|  | 17 |  |  |  |  | 52 |  | 
| 1237 |  |  |  |  |  |  |  | 
| 1238 | 17 |  |  |  |  | 45 | $set->{iterator} | 
| 1239 |  |  |  |  |  |  | } | 
| 1240 |  |  |  |  |  |  |  | 
| 1241 |  |  |  |  |  |  |  | 
| 1242 |  |  |  |  |  |  | sub last($) | 
| 1243 |  |  |  |  |  |  | { | 
| 1244 | 17 |  |  | 17 | 1 | 65 | my $set = shift; | 
| 1245 |  |  |  |  |  |  |  | 
| 1246 | 17 |  |  |  |  | 21 | my $lastEdge     = $#{$set->{edges}}; | 
|  | 17 |  |  |  |  | 36 |  | 
| 1247 | 17 |  |  |  |  | 82 | $set->{iterator} = $set->max; | 
| 1248 | 17 | 100 |  |  |  | 53 | $set->{run}[0]   = $lastEdge ? $lastEdge-1 : undef; | 
| 1249 | 17 |  |  |  |  | 27 | $set->{run}[1]   = $lastEdge; | 
| 1250 |  |  |  |  |  |  |  | 
| 1251 | 17 |  |  |  |  | 48 | $set->{iterator} | 
| 1252 |  |  |  |  |  |  | } | 
| 1253 |  |  |  |  |  |  |  | 
| 1254 |  |  |  |  |  |  |  | 
| 1255 |  |  |  |  |  |  | sub start($$) | 
| 1256 |  |  |  |  |  |  | { | 
| 1257 | 58 |  |  | 58 | 1 | 898 | my($set, $start) = @_; | 
| 1258 |  |  |  |  |  |  |  | 
| 1259 | 58 |  |  |  |  | 92 | $set->{iterator} = undef; | 
| 1260 | 58 | 50 |  |  |  | 110 | defined $start or return undef; | 
| 1261 |  |  |  |  |  |  |  | 
| 1262 | 58 |  |  |  |  | 81 | my $inSet = $set->{negInf}; | 
| 1263 | 58 |  |  |  |  | 67 | my $edges = $set->{edges}; | 
| 1264 |  |  |  |  |  |  |  | 
| 1265 | 58 |  |  |  |  | 136 | for (my $i=0; $i<@$edges; $i++) | 
| 1266 |  |  |  |  |  |  | { | 
| 1267 | 171 | 100 |  |  |  | 4515 | if ($inSet) | 
| 1268 |  |  |  |  |  |  | { | 
| 1269 | 82 | 100 |  |  |  | 157 | if ($start <= $$edges[$i]) | 
| 1270 |  |  |  |  |  |  | { | 
| 1271 | 29 |  |  |  |  | 38 | $set->{iterator} = $start; | 
| 1272 | 29 | 100 |  |  |  | 69 | $set->{run}[0] = $i ? $i-1 : undef; | 
| 1273 | 29 |  |  |  |  | 41 | $set->{run}[1] = $i; | 
| 1274 | 29 |  |  |  |  | 142 | return $start; | 
| 1275 |  |  |  |  |  |  | } | 
| 1276 | 53 |  |  |  |  | 116 | $inSet = 0; | 
| 1277 |  |  |  |  |  |  | } | 
| 1278 |  |  |  |  |  |  | else | 
| 1279 |  |  |  |  |  |  | { | 
| 1280 | 89 | 100 |  |  |  | 269 | if ($start <= $$edges[$i]) | 
| 1281 |  |  |  |  |  |  | { | 
| 1282 | 18 |  |  |  |  | 55 | return undef; | 
| 1283 |  |  |  |  |  |  | } | 
| 1284 | 71 |  |  |  |  | 146 | $inSet = 1; | 
| 1285 |  |  |  |  |  |  | } | 
| 1286 |  |  |  |  |  |  | } | 
| 1287 |  |  |  |  |  |  |  | 
| 1288 | 11 | 100 |  |  |  | 23 | if ($inSet) | 
| 1289 |  |  |  |  |  |  | { | 
| 1290 | 8 |  |  |  |  | 15 | $set->{iterator} = $start; | 
| 1291 | 8 | 100 |  |  |  | 20 | $set->{run}[0]   = @$edges? $#$edges: undef; | 
| 1292 | 8 |  |  |  |  | 13 | $set->{run}[1]   = undef; | 
| 1293 |  |  |  |  |  |  | } | 
| 1294 |  |  |  |  |  |  |  | 
| 1295 | 11 |  |  |  |  | 27 | $set->{iterator} | 
| 1296 |  |  |  |  |  |  | } | 
| 1297 |  |  |  |  |  |  |  | 
| 1298 |  |  |  |  |  |  |  | 
| 1299 | 11 |  |  | 11 | 1 | 50 | sub current($) { shift->{iterator} } | 
| 1300 |  |  |  |  |  |  |  | 
| 1301 |  |  |  |  |  |  |  | 
| 1302 |  |  |  |  |  |  | sub next($) | 
| 1303 |  |  |  |  |  |  | { | 
| 1304 | 44 |  |  | 44 | 1 | 319 | my $set = shift; | 
| 1305 |  |  |  |  |  |  |  | 
| 1306 | 44 | 100 |  |  |  | 123 | defined $set->{iterator} or return $set->first; | 
| 1307 |  |  |  |  |  |  |  | 
| 1308 | 42 |  |  |  |  | 55 | my $run1 = $set->{run}[1]; | 
| 1309 | 42 | 100 |  |  |  | 89 | defined $run1 or return ++$set->{iterator}; | 
| 1310 |  |  |  |  |  |  |  | 
| 1311 | 41 |  |  |  |  | 55 | my $edges = $set->{edges}; | 
| 1312 | 41 | 100 |  |  |  | 120 | $set->{iterator} < $edges->[$run1] and return ++$set->{iterator}; | 
| 1313 |  |  |  |  |  |  |  | 
| 1314 | 13 | 100 |  |  |  | 36 | if    ($run1 < $#$edges-1) | 
|  |  | 100 |  |  |  |  |  | 
| 1315 |  |  |  |  |  |  | { | 
| 1316 | 4 |  |  |  |  | 8 | my $run0         = $run1 + 1; | 
| 1317 | 4 |  |  |  |  | 9 | $set->{run}      = [$run0, $run0+1]; | 
| 1318 | 4 |  |  |  |  | 11 | $set->{iterator} = $edges->[$run0]+1; | 
| 1319 |  |  |  |  |  |  | } | 
| 1320 |  |  |  |  |  |  | elsif ($run1 < $#$edges) | 
| 1321 |  |  |  |  |  |  | { | 
| 1322 | 2 |  |  |  |  | 4 | my $run0         = $run1 + 1; | 
| 1323 | 2 |  |  |  |  | 5 | $set->{run}      = [$run0, undef]; | 
| 1324 | 2 |  |  |  |  | 6 | $set->{iterator} = $edges->[$run0]+1; | 
| 1325 |  |  |  |  |  |  | } | 
| 1326 |  |  |  |  |  |  | else | 
| 1327 |  |  |  |  |  |  | { | 
| 1328 | 7 |  |  |  |  | 16 | $set->{iterator} = undef; | 
| 1329 |  |  |  |  |  |  | } | 
| 1330 |  |  |  |  |  |  |  | 
| 1331 | 13 |  |  |  |  | 35 | $set->{iterator} | 
| 1332 |  |  |  |  |  |  | } | 
| 1333 |  |  |  |  |  |  |  | 
| 1334 |  |  |  |  |  |  |  | 
| 1335 |  |  |  |  |  |  | sub prev($) | 
| 1336 |  |  |  |  |  |  | { | 
| 1337 | 39 |  |  | 39 | 1 | 267 | my $set = shift; | 
| 1338 |  |  |  |  |  |  |  | 
| 1339 | 39 | 100 |  |  |  | 96 | defined $set->{iterator} or return $set->last; | 
| 1340 |  |  |  |  |  |  |  | 
| 1341 | 37 |  |  |  |  | 49 | my $run0 = $set->{run}[0]; | 
| 1342 | 37 | 100 |  |  |  | 71 | defined $run0 or return --$set->{iterator}; | 
| 1343 |  |  |  |  |  |  |  | 
| 1344 | 36 |  |  |  |  | 52 | my $edges = $set->{edges}; | 
| 1345 | 36 | 100 |  |  |  | 128 | $set->{iterator} > $edges->[$run0]+1 and return --$set->{iterator}; | 
| 1346 |  |  |  |  |  |  |  | 
| 1347 | 11 | 100 |  |  |  | 27 | if    ($run0 > 1) | 
|  |  | 100 |  |  |  |  |  | 
| 1348 |  |  |  |  |  |  | { | 
| 1349 | 3 |  |  |  |  | 6 | my $run1         = $run0 - 1; | 
| 1350 | 3 |  |  |  |  | 9 | $set->{run}      = [$run1-1, $run1]; | 
| 1351 | 3 |  |  |  |  | 9 | $set->{iterator} = $edges->[$run1]; | 
| 1352 |  |  |  |  |  |  | } | 
| 1353 |  |  |  |  |  |  | elsif ($run0 > 0) | 
| 1354 |  |  |  |  |  |  | { | 
| 1355 | 1 |  |  |  |  | 3 | my $run1         = $run0 - 1; | 
| 1356 | 1 |  |  |  |  | 4 | $set->{run}      = [undef, $run1]; | 
| 1357 | 1 |  |  |  |  | 4 | $set->{iterator} = $edges->[$run1]; | 
| 1358 |  |  |  |  |  |  | } | 
| 1359 |  |  |  |  |  |  | else | 
| 1360 |  |  |  |  |  |  | { | 
| 1361 | 7 |  |  |  |  | 12 | $set->{iterator} = undef; | 
| 1362 |  |  |  |  |  |  | } | 
| 1363 |  |  |  |  |  |  |  | 
| 1364 | 11 |  |  |  |  | 31 | $set->{iterator} | 
| 1365 |  |  |  |  |  |  | } | 
| 1366 |  |  |  |  |  |  |  | 
| 1367 |  |  |  |  |  |  | sub at | 
| 1368 |  |  |  |  |  |  | { | 
| 1369 | 29 |  |  | 29 | 1 | 36 | my($set, $i) = @_; | 
| 1370 |  |  |  |  |  |  |  | 
| 1371 | 29 | 100 |  |  |  | 89 | $i < 0 ? $set->_at_neg($i) : $set->_at_pos($i) | 
| 1372 |  |  |  |  |  |  | } | 
| 1373 |  |  |  |  |  |  |  | 
| 1374 |  |  |  |  |  |  | sub _at_pos | 
| 1375 |  |  |  |  |  |  | { | 
| 1376 | 14 |  |  | 14 |  | 16 | my($set, $i) = @_; | 
| 1377 |  |  |  |  |  |  |  | 
| 1378 | 14 | 100 |  |  |  | 23 | $set->neg_inf and | 
| 1379 |  |  |  |  |  |  | croak "Set::IntSpan::at: negative infinite set\n"; | 
| 1380 |  |  |  |  |  |  |  | 
| 1381 | 13 |  |  |  |  | 13 | my @edges = @{$set->{edges}}; | 
|  | 13 |  |  |  |  | 37 |  | 
| 1382 |  |  |  |  |  |  |  | 
| 1383 | 13 |  |  |  |  | 33 | while (@edges > 1) | 
| 1384 |  |  |  |  |  |  | { | 
| 1385 | 16 |  |  |  |  | 28 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 1386 |  |  |  |  |  |  |  | 
| 1387 | 16 |  |  |  |  | 34 | my $size = $upper - $lower; | 
| 1388 |  |  |  |  |  |  |  | 
| 1389 | 16 | 100 |  |  |  | 47 | $i < $size and return $lower + 1 + $i; | 
| 1390 |  |  |  |  |  |  |  | 
| 1391 | 10 |  |  |  |  | 29 | $i -= $size; | 
| 1392 |  |  |  |  |  |  | } | 
| 1393 |  |  |  |  |  |  |  | 
| 1394 | 7 | 100 |  |  |  | 32 | @edges ? $edges[0] + 1 + $i : undef | 
| 1395 |  |  |  |  |  |  | } | 
| 1396 |  |  |  |  |  |  |  | 
| 1397 |  |  |  |  |  |  | sub _at_neg | 
| 1398 |  |  |  |  |  |  | { | 
| 1399 | 15 |  |  | 15 |  | 17 | my($set, $i) = @_; | 
| 1400 |  |  |  |  |  |  |  | 
| 1401 | 15 | 100 |  |  |  | 27 | $set->pos_inf and | 
| 1402 |  |  |  |  |  |  | croak "Set::IntSpan::at: positive infinite set\n"; | 
| 1403 |  |  |  |  |  |  |  | 
| 1404 | 14 |  |  |  |  | 15 | my @edges = @{$set->{edges}}; | 
|  | 14 |  |  |  |  | 67 |  | 
| 1405 | 14 |  |  |  |  | 17 | $i++; | 
| 1406 |  |  |  |  |  |  |  | 
| 1407 | 14 |  |  |  |  | 30 | while (@edges > 1) | 
| 1408 |  |  |  |  |  |  | { | 
| 1409 | 19 |  |  |  |  | 31 | my($lower, $upper) = splice(@edges, -2, 2); | 
| 1410 |  |  |  |  |  |  |  | 
| 1411 | 19 |  |  |  |  | 28 | my $size = $upper - $lower; | 
| 1412 |  |  |  |  |  |  |  | 
| 1413 | 19 | 100 |  |  |  | 575 | -$i < $size and return $upper + $i; | 
| 1414 |  |  |  |  |  |  |  | 
| 1415 | 12 |  |  |  |  | 28 | $i += $size; | 
| 1416 |  |  |  |  |  |  | } | 
| 1417 |  |  |  |  |  |  |  | 
| 1418 | 7 | 100 |  |  |  | 32 | @edges ? $edges[0] + $i : undef | 
| 1419 |  |  |  |  |  |  | } | 
| 1420 |  |  |  |  |  |  |  | 
| 1421 |  |  |  |  |  |  | sub ord | 
| 1422 |  |  |  |  |  |  | { | 
| 1423 | 16 |  |  | 16 | 1 | 18 | my($set, $n) = @_; | 
| 1424 |  |  |  |  |  |  |  | 
| 1425 | 16 | 100 |  |  |  | 281 | $set->{negInf} and | 
| 1426 |  |  |  |  |  |  | croak "Set::IntSpan::ord: negative infinite set\n"; | 
| 1427 |  |  |  |  |  |  |  | 
| 1428 | 15 | 50 |  |  |  | 30 | defined $n or return undef; | 
| 1429 |  |  |  |  |  |  |  | 
| 1430 | 15 |  |  |  |  | 13 | my $i = 0; | 
| 1431 | 15 |  |  |  |  | 18 | my @edges = @{$set->{edges}}; | 
|  | 15 |  |  |  |  | 39 |  | 
| 1432 |  |  |  |  |  |  |  | 
| 1433 | 15 |  |  |  |  | 30 | while (@edges) | 
| 1434 |  |  |  |  |  |  | { | 
| 1435 | 21 |  |  |  |  | 33 | my($lower, $upper) = splice(@edges, 0, 2); | 
| 1436 |  |  |  |  |  |  |  | 
| 1437 | 21 | 100 |  |  |  | 55 | $n <= $lower and return undef; | 
| 1438 |  |  |  |  |  |  |  | 
| 1439 | 17 | 100 | 100 |  |  | 71 | if (defined $upper and $upper < $n) | 
| 1440 |  |  |  |  |  |  | { | 
| 1441 | 9 |  |  |  |  | 10 | $i += $upper - $lower; | 
| 1442 | 9 |  |  |  |  | 30 | next; | 
| 1443 |  |  |  |  |  |  | } | 
| 1444 |  |  |  |  |  |  |  | 
| 1445 | 8 |  |  |  |  | 31 | return $i + $n - $lower - 1; | 
| 1446 |  |  |  |  |  |  | } | 
| 1447 |  |  |  |  |  |  |  | 
| 1448 |  |  |  |  |  |  | undef | 
| 1449 | 3 |  |  |  |  | 12 | } | 
| 1450 |  |  |  |  |  |  |  | 
| 1451 |  |  |  |  |  |  | sub slice | 
| 1452 |  |  |  |  |  |  | { | 
| 1453 | 35 |  |  | 35 | 1 | 55 | my($set, $from, $to) = @_; | 
| 1454 |  |  |  |  |  |  |  | 
| 1455 | 35 |  |  |  |  | 71 | $set->{slicing} = 1; | 
| 1456 | 35 |  |  |  |  | 130 | my $slice = $set->_splice($from, $to - $from + 1); | 
| 1457 | 33 |  |  |  |  | 59 | $set->{slicing} = 0; | 
| 1458 |  |  |  |  |  |  |  | 
| 1459 | 33 |  |  |  |  | 74 | $slice | 
| 1460 |  |  |  |  |  |  | } | 
| 1461 |  |  |  |  |  |  |  | 
| 1462 |  |  |  |  |  |  | sub _splice | 
| 1463 |  |  |  |  |  |  | { | 
| 1464 | 233 |  |  | 233 |  | 393 | my($set, $offset, $length) = @_; | 
| 1465 |  |  |  |  |  |  |  | 
| 1466 | 233 | 100 |  |  |  | 617 | $offset < 0 | 
| 1467 |  |  |  |  |  |  | ? $set->_splice_neg($offset, $length) | 
| 1468 |  |  |  |  |  |  | : $set->_splice_pos($offset, $length) | 
| 1469 |  |  |  |  |  |  | } | 
| 1470 |  |  |  |  |  |  |  | 
| 1471 |  |  |  |  |  |  | sub _splice_pos | 
| 1472 |  |  |  |  |  |  | { | 
| 1473 | 116 |  |  | 116 |  | 139 | my($set, $offset, $length) = @_; | 
| 1474 |  |  |  |  |  |  |  | 
| 1475 | 116 | 100 |  |  |  | 175 | $set->neg_inf and | 
| 1476 |  |  |  |  |  |  | croak "Set::IntSpan::slice: negative infinite set\n"; | 
| 1477 |  |  |  |  |  |  |  | 
| 1478 | 114 |  |  |  |  | 133 | my @edges = @{$set->{edges}}; | 
|  | 114 |  |  |  |  | 287 |  | 
| 1479 | 114 |  |  |  |  | 227 | my $slice = new Set::IntSpan; | 
| 1480 |  |  |  |  |  |  |  | 
| 1481 | 114 |  |  |  |  | 232 | while (@edges > 1) | 
| 1482 |  |  |  |  |  |  | { | 
| 1483 | 151 |  |  |  |  | 275 | my ($lower, $upper) = @edges[0,1]; | 
| 1484 | 151 |  |  |  |  | 163 | my $size = $upper - $lower; | 
| 1485 |  |  |  |  |  |  |  | 
| 1486 | 151 | 100 |  |  |  | 276 | $offset < $size and last; | 
| 1487 |  |  |  |  |  |  |  | 
| 1488 | 62 |  |  |  |  | 79 | splice(@edges, 0, 2); | 
| 1489 | 62 |  |  |  |  | 138 | $offset -= $size; | 
| 1490 |  |  |  |  |  |  | } | 
| 1491 |  |  |  |  |  |  |  | 
| 1492 |  |  |  |  |  |  | @edges or | 
| 1493 | 114 | 100 |  |  |  | 271 | return $slice;  # empty set | 
| 1494 |  |  |  |  |  |  |  | 
| 1495 | 102 |  |  |  |  | 115 | $edges[0] += $offset; | 
| 1496 |  |  |  |  |  |  |  | 
| 1497 | 102 |  |  |  |  | 180 | $slice->{edges} = $set->_splice_length(\@edges, $length); | 
| 1498 | 101 |  |  |  |  | 368 | $slice | 
| 1499 |  |  |  |  |  |  | } | 
| 1500 |  |  |  |  |  |  |  | 
| 1501 |  |  |  |  |  |  | sub _splice_neg | 
| 1502 |  |  |  |  |  |  | { | 
| 1503 | 117 |  |  | 117 |  | 143 | my($set, $offset, $length) = @_; | 
| 1504 |  |  |  |  |  |  |  | 
| 1505 | 117 | 100 |  |  |  | 207 | $set->pos_inf and | 
| 1506 |  |  |  |  |  |  | croak "Set::IntSpan::slice: positive infinite set\n"; | 
| 1507 |  |  |  |  |  |  |  | 
| 1508 | 114 |  |  |  |  | 124 | my @edges = @{$set->{edges}}; | 
|  | 114 |  |  |  |  | 379 |  | 
| 1509 | 114 |  |  |  |  | 479 | my $slice = new Set::IntSpan; | 
| 1510 |  |  |  |  |  |  |  | 
| 1511 | 114 |  |  |  |  | 140 | my @slice; | 
| 1512 | 114 |  |  |  |  | 120 | $offset++; | 
| 1513 |  |  |  |  |  |  |  | 
| 1514 | 114 |  |  |  |  | 224 | while (@edges > 1) | 
| 1515 |  |  |  |  |  |  | { | 
| 1516 | 193 |  |  |  |  | 345 | my ($lower, $upper) = @edges[-2,-1]; | 
| 1517 | 193 |  |  |  |  | 240 | my $size = $upper - $lower; | 
| 1518 |  |  |  |  |  |  |  | 
| 1519 | 193 | 100 |  |  |  | 697 | -$offset < $size and last; | 
| 1520 |  |  |  |  |  |  |  | 
| 1521 | 101 |  |  |  |  | 233 | unshift @slice, splice(@edges, -2, 2); | 
| 1522 | 101 |  |  |  |  | 257 | $offset += $size; | 
| 1523 |  |  |  |  |  |  | } | 
| 1524 |  |  |  |  |  |  |  | 
| 1525 | 114 | 100 |  |  |  | 227 | if (@edges) | 
|  |  | 100 |  |  |  |  |  | 
| 1526 |  |  |  |  |  |  | { | 
| 1527 | 100 |  |  |  |  | 139 | my $upper = pop @edges; | 
| 1528 | 100 |  |  |  |  | 261 | unshift @slice, $upper+$offset-1, $upper; | 
| 1529 |  |  |  |  |  |  | } | 
| 1530 |  |  |  |  |  |  | elsif ($set->{slicing}) | 
| 1531 |  |  |  |  |  |  | { | 
| 1532 | 2 |  |  |  |  | 4 | $length += $offset-1; | 
| 1533 |  |  |  |  |  |  | } | 
| 1534 |  |  |  |  |  |  |  | 
| 1535 | 114 |  |  |  |  | 271 | $slice->{edges} = $set->_splice_length(\@slice, $length); | 
| 1536 | 114 |  |  |  |  | 405 | $slice | 
| 1537 |  |  |  |  |  |  | } | 
| 1538 |  |  |  |  |  |  |  | 
| 1539 |  |  |  |  |  |  | sub _splice_length | 
| 1540 |  |  |  |  |  |  | { | 
| 1541 | 216 |  |  | 216 |  | 276 | my($set, $edges, $length) = @_; | 
| 1542 |  |  |  |  |  |  |  | 
| 1543 | 216 | 100 |  |  |  | 479 | not defined $length   and return $edges;  # everything | 
| 1544 | 193 | 100 |  |  |  | 445 | $length<0 and return $set->_splice_length_neg($edges, -$length); | 
| 1545 | 115 | 100 |  |  |  | 297 | $length>0 and return $set->_splice_length_pos($edges,  $length); | 
| 1546 |  |  |  |  |  |  |  | 
| 1547 | 12 |  |  |  |  | 145 | []  # $length==0 | 
| 1548 |  |  |  |  |  |  | } | 
| 1549 |  |  |  |  |  |  |  | 
| 1550 |  |  |  |  |  |  | sub _splice_length_pos | 
| 1551 |  |  |  |  |  |  | { | 
| 1552 | 103 |  |  | 103 |  | 113 | my($set, $edges, $length) = @_; | 
| 1553 |  |  |  |  |  |  |  | 
| 1554 | 103 |  |  |  |  | 91 | my @slice; | 
| 1555 |  |  |  |  |  |  |  | 
| 1556 | 103 |  |  |  |  | 203 | while (@$edges > 1) | 
| 1557 |  |  |  |  |  |  | { | 
| 1558 | 125 |  |  |  |  | 206 | my ($lower, $upper) = @$edges[0,1]; | 
| 1559 | 125 |  |  |  |  | 129 | my $size = $upper - $lower; | 
| 1560 |  |  |  |  |  |  |  | 
| 1561 | 125 | 100 |  |  |  | 214 | $length <= $size and last; | 
| 1562 |  |  |  |  |  |  |  | 
| 1563 | 54 |  |  |  |  | 95 | push @slice, splice(@$edges, 0, 2); | 
| 1564 | 54 |  |  |  |  | 131 | $length -= $size; | 
| 1565 |  |  |  |  |  |  | } | 
| 1566 |  |  |  |  |  |  |  | 
| 1567 | 103 | 100 |  |  |  | 175 | if (@$edges) | 
| 1568 |  |  |  |  |  |  | { | 
| 1569 | 84 |  |  |  |  | 98 | my $lower = shift @$edges; | 
| 1570 | 84 |  |  |  |  | 141 | push @slice, $lower, $lower+$length; | 
| 1571 |  |  |  |  |  |  | } | 
| 1572 |  |  |  |  |  |  |  | 
| 1573 |  |  |  |  |  |  | \@slice | 
| 1574 | 103 |  |  |  |  | 264 | } | 
| 1575 |  |  |  |  |  |  |  | 
| 1576 |  |  |  |  |  |  | sub _splice_length_neg | 
| 1577 |  |  |  |  |  |  | { | 
| 1578 | 78 |  |  | 78 |  | 94 | my($set, $edges, $length) = @_; | 
| 1579 |  |  |  |  |  |  |  | 
| 1580 | 78 | 100 |  |  |  | 136 | $set->pos_inf and | 
| 1581 |  |  |  |  |  |  | croak "Set::IntSpan::slice: positive infinite set\n"; | 
| 1582 |  |  |  |  |  |  |  | 
| 1583 | 77 |  |  |  |  | 178 | while (@$edges > 1) | 
| 1584 |  |  |  |  |  |  | { | 
| 1585 | 126 |  |  |  |  | 199 | my($lower, $upper) = @$edges[-2,-1]; | 
| 1586 | 126 |  |  |  |  | 150 | my $size = $upper - $lower; | 
| 1587 |  |  |  |  |  |  |  | 
| 1588 | 126 | 100 |  |  |  | 227 | $length < $size and last; | 
| 1589 |  |  |  |  |  |  |  | 
| 1590 | 73 |  |  |  |  | 98 | splice(@$edges, -2, 2); | 
| 1591 | 73 |  |  |  |  | 172 | $length -= $size; | 
| 1592 |  |  |  |  |  |  | } | 
| 1593 |  |  |  |  |  |  |  | 
| 1594 | 77 | 100 |  |  |  | 141 | if (@$edges) | 
| 1595 |  |  |  |  |  |  | { | 
| 1596 | 53 |  |  |  |  | 73 | $edges->[-1] -= $length; | 
| 1597 |  |  |  |  |  |  | } | 
| 1598 |  |  |  |  |  |  |  | 
| 1599 |  |  |  |  |  |  | $edges | 
| 1600 | 77 |  |  |  |  | 178 | } | 
| 1601 |  |  |  |  |  |  |  | 
| 1602 |  |  |  |  |  |  | 1 | 
| 1603 |  |  |  |  |  |  |  | 
| 1604 |  |  |  |  |  |  | __END__ |