Filename | /usr/share/perl5/Set/Infinite/_recurrence.pm |
Statements | Executed 20 statements in 1.43ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 34µs | 44µs | BEGIN@7 | Set::Infinite::_recurrence::
1 | 1 | 1 | 19µs | 19µs | BEGIN@17 | Set::Infinite::_recurrence::
1 | 1 | 1 | 16µs | 58µs | BEGIN@15 | Set::Infinite::_recurrence::
1 | 1 | 1 | 14µs | 80µs | BEGIN@9 | Set::Infinite::_recurrence::
1 | 1 | 1 | 12µs | 67µs | BEGIN@12 | Set::Infinite::_recurrence::
1 | 1 | 1 | 10µs | 44µs | BEGIN@10 | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | __ANON__[:104] | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | __ANON__[:231] | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | __ANON__[:243] | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | __ANON__[:264] | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | __ANON__[:269] | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | __ANON__[:55] | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | __ANON__[:74] | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | _is_recurrence | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | _recurrence | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | intersection | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | is_forever | Set::Infinite::_recurrence::
0 | 0 | 0 | 0s | 0s | union | Set::Infinite::_recurrence::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # Copyright (c) 2003 Flavio Soibelmann Glock. All rights reserved. | ||||
2 | # This program is free software; you can redistribute it and/or | ||||
3 | # modify it under the same terms as Perl itself. | ||||
4 | |||||
5 | package Set::Infinite::_recurrence; | ||||
6 | |||||
7 | 3 | 54µs | 2 | 53µs | # spent 44µs (34+10) within Set::Infinite::_recurrence::BEGIN@7 which was called:
# once (34µs+10µs) by DateTime::Set::BEGIN@11 at line 7 # spent 44µs making 1 call to Set::Infinite::_recurrence::BEGIN@7
# spent 10µs making 1 call to strict::import |
8 | |||||
9 | 3 | 47µs | 2 | 145µs | # spent 80µs (14+66) within Set::Infinite::_recurrence::BEGIN@9 which was called:
# once (14µs+66µs) by DateTime::Set::BEGIN@11 at line 9 # spent 80µs making 1 call to Set::Infinite::_recurrence::BEGIN@9
# spent 66µs making 1 call to constant::import |
10 | 3 | 34µs | 2 | 78µs | # spent 44µs (10+34) within Set::Infinite::_recurrence::BEGIN@10 which was called:
# once (10µs+34µs) by DateTime::Set::BEGIN@11 at line 10 # spent 44µs making 1 call to Set::Infinite::_recurrence::BEGIN@10
# spent 34µs making 1 call to constant::import |
11 | |||||
12 | 3 | 43µs | 2 | 123µs | # spent 67µs (12+55) within Set::Infinite::_recurrence::BEGIN@12 which was called:
# once (12µs+55µs) by DateTime::Set::BEGIN@11 at line 12 # spent 67µs making 1 call to Set::Infinite::_recurrence::BEGIN@12
# spent 56µs making 1 call to vars::import |
13 | |||||
14 | 1 | 16µs | @ISA = qw( Set::Infinite ); | ||
15 | 3 | 303µs | 3 | 99µs | # spent 58µs (16+42) within Set::Infinite::_recurrence::BEGIN@15 which was called:
# once (16µs+42µs) by DateTime::Set::BEGIN@11 at line 15 # spent 58µs making 1 call to Set::Infinite::_recurrence::BEGIN@15
# spent 22µs making 1 call to Exporter::import
# spent 20µs making 1 call to UNIVERSAL::VERSION |
16 | |||||
17 | # spent 19µs within Set::Infinite::_recurrence::BEGIN@17 which was called:
# once (19µs+0s) by DateTime::Set::BEGIN@11 at line 75 | ||||
18 | 1 | 400ns | $PRETTY_PRINT = 1; # enable Set::Infinite debug | ||
19 | 1 | 200ns | $max_iterate = 20; | ||
20 | |||||
21 | # TODO: inherit %Set::Infinite::_first / _last | ||||
22 | # in a more "object oriented" way | ||||
23 | |||||
24 | $Set::Infinite::_first{_recurrence} = | ||||
25 | sub { | ||||
26 | my $self = $_[0]; | ||||
27 | my ($callback_next, $callback_previous) = @{ $self->{param} }; | ||||
28 | my ($min, $min_open) = $self->{parent}->min_a; | ||||
29 | |||||
30 | my ( $min1, $min2 ); | ||||
31 | $min1 = $callback_next->( $min ); | ||||
32 | if ( ! $min_open ) | ||||
33 | { | ||||
34 | $min2 = $callback_previous->( $min1 ); | ||||
35 | $min1 = $min2 if defined $min2 && $min == $min2; | ||||
36 | } | ||||
37 | |||||
38 | my $start = $callback_next->( $min1 ); | ||||
39 | my $end = $self->{parent}->max; | ||||
40 | |||||
41 | #print STDERR "set "; | ||||
42 | #print STDERR $start->datetime | ||||
43 | # unless $start == INFINITY; | ||||
44 | #print STDERR " - " ; | ||||
45 | #print STDERR $end->datetime | ||||
46 | # unless $end == INFINITY; | ||||
47 | #print STDERR "\n"; | ||||
48 | |||||
49 | return ( $self->new( $min1 ), undef ) | ||||
50 | if $start > $end; | ||||
51 | |||||
52 | return ( $self->new( $min1 ), | ||||
53 | $self->new( $start, $end )-> | ||||
54 | _function( '_recurrence', @{ $self->{param} } ) ); | ||||
55 | 1 | 10µs | }; | ||
56 | $Set::Infinite::_last{_recurrence} = | ||||
57 | sub { | ||||
58 | my $self = $_[0]; | ||||
59 | my ($callback_next, $callback_previous) = @{ $self->{param} }; | ||||
60 | my ($max, $max_open) = $self->{parent}->max_a; | ||||
61 | |||||
62 | my ( $max1, $max2 ); | ||||
63 | $max1 = $callback_previous->( $max ); | ||||
64 | if ( ! $max_open ) | ||||
65 | { | ||||
66 | $max2 = $callback_next->( $max1 ); | ||||
67 | $max1 = $max2 if $max == $max2; | ||||
68 | } | ||||
69 | |||||
70 | return ( $self->new( $max1 ), | ||||
71 | $self->new( $self->{parent}->min, | ||||
72 | $callback_previous->( $max1 ) )-> | ||||
73 | _function( '_recurrence', @{ $self->{param} } ) ); | ||||
74 | 1 | 8µs | }; | ||
75 | 1 | 914µs | 1 | 19µs | } # spent 19µs making 1 call to Set::Infinite::_recurrence::BEGIN@17 |
76 | |||||
77 | # $si->_recurrence( | ||||
78 | # \&callback_next, \&callback_previous ) | ||||
79 | # | ||||
80 | # Generates "recurrences" from a callback. | ||||
81 | # These recurrences are simple lists of dates. | ||||
82 | # | ||||
83 | # The recurrence generation is based on an idea from Dave Rolsky. | ||||
84 | # | ||||
85 | |||||
86 | # use Data::Dumper; | ||||
87 | # use Carp qw(cluck); | ||||
88 | |||||
89 | sub _recurrence { | ||||
90 | my $set = shift; | ||||
91 | my ( $callback_next, $callback_previous, $delta ) = @_; | ||||
92 | |||||
93 | $delta->{count} = 0 unless defined $delta->{delta}; | ||||
94 | |||||
95 | # warn "reusing delta: ". $delta->{count} if defined $delta->{delta}; | ||||
96 | # warn Dumper( $delta ); | ||||
97 | |||||
98 | if ( $#{ $set->{list} } != 0 || $set->is_too_complex ) | ||||
99 | { | ||||
100 | return $set->iterate( | ||||
101 | sub { | ||||
102 | $_[0]->_recurrence( | ||||
103 | $callback_next, $callback_previous, $delta ) | ||||
104 | } ); | ||||
105 | } | ||||
106 | # $set is a span | ||||
107 | my $result; | ||||
108 | if ($set->min != NEG_INFINITY && $set->max != INFINITY) | ||||
109 | { | ||||
110 | # print STDERR " finite set\n"; | ||||
111 | my ($min, $min_open) = $set->min_a; | ||||
112 | my ($max, $max_open) = $set->max_a; | ||||
113 | |||||
114 | my ( $min1, $min2 ); | ||||
115 | $min1 = $callback_next->( $min ); | ||||
116 | if ( ! $min_open ) | ||||
117 | { | ||||
118 | $min2 = $callback_previous->( $min1 ); | ||||
119 | $min1 = $min2 if defined $min2 && $min == $min2; | ||||
120 | } | ||||
121 | |||||
122 | $result = $set->new(); | ||||
123 | |||||
124 | # get "delta" - abort if this will take too much time. | ||||
125 | |||||
126 | unless ( defined $delta->{max_delta} ) | ||||
127 | { | ||||
128 | for ( $delta->{count} .. 10 ) | ||||
129 | { | ||||
130 | if ( $max_open ) | ||||
131 | { | ||||
132 | return $result if $min1 >= $max; | ||||
133 | } | ||||
134 | else | ||||
135 | { | ||||
136 | return $result if $min1 > $max; | ||||
137 | } | ||||
138 | push @{ $result->{list} }, | ||||
139 | { a => $min1, b => $min1, open_begin => 0, open_end => 0 }; | ||||
140 | $min2 = $callback_next->( $min1 ); | ||||
141 | |||||
142 | if ( $delta->{delta} ) | ||||
143 | { | ||||
144 | $delta->{delta} += $min2 - $min1; | ||||
145 | } | ||||
146 | else | ||||
147 | { | ||||
148 | $delta->{delta} = $min2 - $min1; | ||||
149 | } | ||||
150 | $delta->{count}++; | ||||
151 | $min1 = $min2; | ||||
152 | } | ||||
153 | |||||
154 | $delta->{max_delta} = $delta->{delta} * 40; | ||||
155 | } | ||||
156 | |||||
157 | if ( $max < $min + $delta->{max_delta} ) | ||||
158 | { | ||||
159 | for ( 1 .. 200 ) | ||||
160 | { | ||||
161 | if ( $max_open ) | ||||
162 | { | ||||
163 | return $result if $min1 >= $max; | ||||
164 | } | ||||
165 | else | ||||
166 | { | ||||
167 | return $result if $min1 > $max; | ||||
168 | } | ||||
169 | push @{ $result->{list} }, | ||||
170 | { a => $min1, b => $min1, open_begin => 0, open_end => 0 }; | ||||
171 | $min1 = $callback_next->( $min1 ); | ||||
172 | } | ||||
173 | } | ||||
174 | |||||
175 | # cluck "give up"; | ||||
176 | } | ||||
177 | |||||
178 | # return a "_function", such that we can backtrack later. | ||||
179 | my $func = $set->_function( '_recurrence', $callback_next, $callback_previous, $delta ); | ||||
180 | |||||
181 | # removed - returning $result doesn't help on speed | ||||
182 | ## return $func->_function2( 'union', $result ) if $result; | ||||
183 | |||||
184 | return $func; | ||||
185 | } | ||||
186 | |||||
187 | sub is_forever | ||||
188 | { | ||||
189 | $#{ $_[0]->{list} } == 0 && | ||||
190 | $_[0]->max == INFINITY && | ||||
191 | $_[0]->min == NEG_INFINITY | ||||
192 | } | ||||
193 | |||||
194 | sub _is_recurrence | ||||
195 | { | ||||
196 | exists $_[0]->{method} && | ||||
197 | $_[0]->{method} eq '_recurrence' && | ||||
198 | $_[0]->{parent}->is_forever | ||||
199 | } | ||||
200 | |||||
201 | sub intersection | ||||
202 | { | ||||
203 | my ($s1, $s2) = (shift,shift); | ||||
204 | |||||
205 | if ( exists $s1->{method} && $s1->{method} eq '_recurrence' ) | ||||
206 | { | ||||
207 | # optimize: recurrence && span | ||||
208 | return $s1->{parent}-> | ||||
209 | intersection( $s2, @_ )-> | ||||
210 | _recurrence( @{ $s1->{param} } ) | ||||
211 | unless ref($s2) && exists $s2->{method}; | ||||
212 | |||||
213 | # optimize: recurrence && recurrence | ||||
214 | if ( $s1->{parent}->is_forever && | ||||
215 | ref($s2) && _is_recurrence( $s2 ) ) | ||||
216 | { | ||||
217 | my ( $next1, $previous1 ) = @{ $s1->{param} }; | ||||
218 | my ( $next2, $previous2 ) = @{ $s2->{param} }; | ||||
219 | return $s1->{parent}->_function( '_recurrence', | ||||
220 | sub { | ||||
221 | # intersection of parent 'next' callbacks | ||||
222 | my ($n1, $n2); | ||||
223 | my $iterate = 0; | ||||
224 | $n2 = $next2->( $_[0] ); | ||||
225 | while(1) { | ||||
226 | $n1 = $next1->( $previous1->( $n2 ) ); | ||||
227 | return $n1 if $n1 == $n2; | ||||
228 | $n2 = $next2->( $previous2->( $n1 ) ); | ||||
229 | return if $iterate++ == $max_iterate; | ||||
230 | } | ||||
231 | }, | ||||
232 | sub { | ||||
233 | # intersection of parent 'previous' callbacks | ||||
234 | my ($p1, $p2); | ||||
235 | my $iterate = 0; | ||||
236 | $p2 = $previous2->( $_[0] ); | ||||
237 | while(1) { | ||||
238 | $p1 = $previous1->( $next1->( $p2 ) ); | ||||
239 | return $p1 if $p1 == $p2; | ||||
240 | $p2 = $previous2->( $next2->( $p1 ) ); | ||||
241 | return if $iterate++ == $max_iterate; | ||||
242 | } | ||||
243 | }, | ||||
244 | ); | ||||
245 | } | ||||
246 | } | ||||
247 | return $s1->SUPER::intersection( $s2, @_ ); | ||||
248 | } | ||||
249 | |||||
250 | sub union | ||||
251 | { | ||||
252 | my ($s1, $s2) = (shift,shift); | ||||
253 | if ( $s1->_is_recurrence && | ||||
254 | ref($s2) && _is_recurrence( $s2 ) ) | ||||
255 | { | ||||
256 | # optimize: recurrence || recurrence | ||||
257 | my ( $next1, $previous1 ) = @{ $s1->{param} }; | ||||
258 | my ( $next2, $previous2 ) = @{ $s2->{param} }; | ||||
259 | return $s1->{parent}->_function( '_recurrence', | ||||
260 | sub { # next | ||||
261 | my $n1 = $next1->( $_[0] ); | ||||
262 | my $n2 = $next2->( $_[0] ); | ||||
263 | return $n1 < $n2 ? $n1 : $n2; | ||||
264 | }, | ||||
265 | sub { # previous | ||||
266 | my $p1 = $previous1->( $_[0] ); | ||||
267 | my $p2 = $previous2->( $_[0] ); | ||||
268 | return $p1 > $p2 ? $p1 : $p2; | ||||
269 | }, | ||||
270 | ); | ||||
271 | } | ||||
272 | return $s1->SUPER::union( $s2, @_ ); | ||||
273 | } | ||||
274 | |||||
275 | =head1 NAME | ||||
276 | |||||
- - |