Filename | /var/www/foswikidev/core/lib/Foswiki/ListIterator.pm |
Statements | Executed 953215 statements in 1.27s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
67905 | 4 | 4 | 446ms | 531ms | next | Foswiki::ListIterator::
136052 | 7 | 5 | 396ms | 396ms | hasNext | Foswiki::ListIterator::
227 | 5 | 4 | 2.23ms | 2.23ms | new | Foswiki::ListIterator::
80 | 1 | 1 | 206µs | 206µs | reset | Foswiki::ListIterator::
24 | 1 | 1 | 57µs | 57µs | all | Foswiki::ListIterator::
1 | 1 | 1 | 14µs | 37µs | BEGIN@22 | Foswiki::ListIterator::
1 | 1 | 1 | 13µs | 26µs | BEGIN@16 | Foswiki::ListIterator::
1 | 1 | 1 | 9µs | 13µs | BEGIN@17 | Foswiki::ListIterator::
1 | 1 | 1 | 5µs | 5µs | BEGIN@24 | Foswiki::ListIterator::
1 | 1 | 1 | 4µs | 4µs | BEGIN@19 | Foswiki::ListIterator::
0 | 0 | 0 | 0s | 0s | skip | Foswiki::ListIterator::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::ListIterator | ||||
6 | *implements* Foswiki::Iterator | ||||
7 | |||||
8 | Iterator over a perl list | ||||
9 | |||||
10 | WARNING: this Iterator will skip any elements that are == undef. | ||||
11 | SMELL: hasNext should not 'return 1 if defined($this->{next}), but rather use a boolean - to allow array elements to be undef too. | ||||
12 | |||||
13 | =cut | ||||
14 | |||||
15 | package Foswiki::ListIterator; | ||||
16 | 2 | 30µs | 2 | 39µs | # spent 26µs (13+13) within Foswiki::ListIterator::BEGIN@16 which was called:
# once (13µs+13µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 16 # spent 26µs making 1 call to Foswiki::ListIterator::BEGIN@16
# spent 13µs making 1 call to strict::import |
17 | 2 | 23µs | 2 | 17µs | # spent 13µs (9+4) within Foswiki::ListIterator::BEGIN@17 which was called:
# once (9µs+4µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 17 # spent 13µs making 1 call to Foswiki::ListIterator::BEGIN@17
# spent 4µs making 1 call to warnings::import |
18 | |||||
19 | 2 | 35µs | 1 | 4µs | # spent 4µs within Foswiki::ListIterator::BEGIN@19 which was called:
# once (4µs+0s) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 19 # spent 4µs making 1 call to Foswiki::ListIterator::BEGIN@19 |
20 | 1 | 6µs | our @ISA = ('Foswiki::Iterator'); | ||
21 | |||||
22 | 2 | 53µs | 2 | 61µs | # spent 37µs (14+24) within Foswiki::ListIterator::BEGIN@22 which was called:
# once (14µs+24µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 22 # spent 37µs making 1 call to Foswiki::ListIterator::BEGIN@22
# spent 24µs making 1 call to Exporter::import |
23 | |||||
24 | # spent 5µs within Foswiki::ListIterator::BEGIN@24 which was called:
# once (5µs+0s) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 29 | ||||
25 | 1 | 5µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
26 | require locale; | ||||
27 | import locale(); | ||||
28 | } | ||||
29 | 1 | 549µs | 1 | 5µs | } # spent 5µs making 1 call to Foswiki::ListIterator::BEGIN@24 |
30 | |||||
31 | =begin TML | ||||
32 | |||||
33 | ---++ new(\@list) | ||||
34 | |||||
35 | Create a new iterator over the given list. Designed primarily for operations | ||||
36 | over fully defined lists of object references. The list is not damaged in | ||||
37 | any way. | ||||
38 | |||||
39 | =cut | ||||
40 | |||||
41 | # spent 2.23ms within Foswiki::ListIterator::new which was called 227 times, avg 10µs/call:
# 80 times (1.26ms+0s) by Foswiki::Search::InfoCache::new at line 60 of /var/www/foswikidev/core/lib/Foswiki/Search/InfoCache.pm, avg 16µs/call
# 80 times (548µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::getWebIterator at line 213 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 7µs/call
# 40 times (282µs+0s) by Foswiki::Store::Rcs::Store::eachTopic at line 593 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm, avg 7µs/call
# 26 times (132µs+0s) by Foswiki::Store::Rcs::Store::eachWeb at line 617 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm, avg 5µs/call
# once (13µs+0s) by Foswiki::Users::BaseUserMapping::eachGroupMember at line 301 of /var/www/foswikidev/core/lib/Foswiki/Users/BaseUserMapping.pm | ||||
42 | 227 | 243µs | my ( $class, $list ) = @_; | ||
43 | |||||
44 | 227 | 92µs | $list = [] unless defined $list; | ||
45 | |||||
46 | ASSERT( UNIVERSAL::isa( $list, 'ARRAY' ) ) if DEBUG; | ||||
47 | |||||
48 | 227 | 1.36ms | my $this = bless( | ||
49 | { | ||||
50 | list => $list, | ||||
51 | index => 0, | ||||
52 | process => undef, | ||||
53 | filter => undef, | ||||
54 | next => undef, | ||||
55 | }, | ||||
56 | $class | ||||
57 | ); | ||||
58 | 227 | 961µs | return $this; | ||
59 | } | ||||
60 | |||||
61 | =begin TML | ||||
62 | |||||
63 | ---++ hasNext() -> $boolean | ||||
64 | |||||
65 | Returns false when the iterator is exhausted. | ||||
66 | |||||
67 | <verbatim> | ||||
68 | my $it = new Foswiki::ListIterator(\@list); | ||||
69 | while ($it->hasNext()) { | ||||
70 | ... | ||||
71 | </verbatim> | ||||
72 | |||||
73 | =cut | ||||
74 | |||||
75 | # spent 396ms within Foswiki::ListIterator::hasNext which was called 136052 times, avg 3µs/call:
# 67905 times (85.1ms+0s) by Foswiki::ListIterator::next at line 181, avg 1µs/call
# 46280 times (214ms+0s) by Foswiki::Iterator::FilterIterator::hasNext at line 71 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 5µs/call
# 17600 times (72.7ms+0s) by Foswiki::Search::ResultSet::hasNext at line 105 of /var/www/foswikidev/core/lib/Foswiki/Search/ResultSet.pm, avg 4µs/call
# 4240 times (23.7ms+0s) by Foswiki::Iterator::FilterIterator::hasNext at line 73 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 6µs/call
# 24 times (88µs+0s) by Foswiki::deepWebList at line 1658 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 4µs/call
# 2 times (12µs+0s) by Foswiki::deepWebList at line 1654 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 6µs/call
# once (8µs+0s) by Foswiki::UserMapping::isInGroup at line 427 of /var/www/foswikidev/core/lib/Foswiki/UserMapping.pm | ||||
76 | 136052 | 50.8ms | my ($this) = @_; | ||
77 | 136052 | 287ms | return 1 | ||
78 | if defined( $this->{next} ) | ||||
79 | ; #SMELL: this is still wrong if the array element == undef, but at least means zero is an element | ||||
80 | 68147 | 8.35ms | my $n; | ||
81 | do { | ||||
82 | if ( $this->{list} && $this->{index} < scalar( @{ $this->{list} } ) ) { | ||||
83 | $n = $this->{list}->[ $this->{index}++ ]; | ||||
84 | } | ||||
85 | else { | ||||
86 | 242 | 1.16ms | return 0; | ||
87 | } | ||||
88 | 68147 | 154ms | } while ( $this->{filter} && !&{ $this->{filter} }($n) ); | ||
89 | 67905 | 24.7ms | $this->{next} = $n; | ||
90 | print STDERR "ListIterator::hasNext -> $this->{index} == $this->{next}\n" | ||||
91 | if Foswiki::Iterator::MONITOR; | ||||
92 | 67905 | 313ms | return 1; | ||
93 | } | ||||
94 | |||||
95 | =begin TML | ||||
96 | |||||
97 | ---++ skip(count) -> $countremaining | ||||
98 | |||||
99 | skip X elements (returns 0 if successful, or number of elements remaining to skip if there are not enough elements to skip) | ||||
100 | skip must set up next as though hasNext was called. | ||||
101 | |||||
102 | =cut | ||||
103 | |||||
104 | sub skip { | ||||
105 | my $this = shift; | ||||
106 | my $count = shift; | ||||
107 | |||||
108 | if ( defined( $this->{next} ) ) { | ||||
109 | $count--; | ||||
110 | } | ||||
111 | |||||
112 | $count ||= 0; | ||||
113 | |||||
114 | return 0 if ( $count <= 0 ); | ||||
115 | print STDERR | ||||
116 | "--------------------------------------------ListIterator::skip($count) $this->{index}, " | ||||
117 | . scalar( @{ $this->{list} } ) . "\n" | ||||
118 | if Foswiki::Iterator::MONITOR; | ||||
119 | |||||
120 | my $length = scalar( @{ $this->{list} } ); | ||||
121 | |||||
122 | if ( ( $this->{index} + $count ) >= $length ) { | ||||
123 | |||||
124 | #list too small | ||||
125 | $count = $this->{index} + $count - $length; | ||||
126 | $this->{index} = 1 + $length; | ||||
127 | } | ||||
128 | else { | ||||
129 | $this->{index} += $count; | ||||
130 | $count = 0; | ||||
131 | } | ||||
132 | $this->{next} = undef; | ||||
133 | my $hasnext = $this->hasNext(); | ||||
134 | if ($hasnext) { | ||||
135 | $count--; | ||||
136 | } | ||||
137 | print STDERR | ||||
138 | "--------------------------------------------ListIterator::skip() => $this->{index} $count, $hasnext\n" | ||||
139 | if Foswiki::Iterator::MONITOR; | ||||
140 | |||||
141 | return $count; | ||||
142 | } | ||||
143 | |||||
144 | =begin TML | ||||
145 | |||||
146 | ---++ next() -> $data | ||||
147 | |||||
148 | Return the next entry in the list. | ||||
149 | |||||
150 | The iterator object can be customised to pre- and post-process entries from | ||||
151 | the list before returning them. This is done by setting two fields in the | ||||
152 | iterator object: | ||||
153 | |||||
154 | * ={filter}= can be defined to be a sub that filters each entry. The entry | ||||
155 | will be ignored (next() will not return it) if the filter returns false. | ||||
156 | * ={process}= can be defined to be a sub to process each entry before it | ||||
157 | is returned by next. The value returned from next is the value returned | ||||
158 | by the process function. | ||||
159 | |||||
160 | For example, | ||||
161 | <verbatim> | ||||
162 | my @list = ( 1, 2, 3 ); | ||||
163 | |||||
164 | my $it = new Foswiki::ListIterator(\@list); | ||||
165 | $it->{filter} = sub { return $_[0] != 2 }; | ||||
166 | $it->{process} = sub { return $_[0] + 1 }; | ||||
167 | while ($it->hasNext()) { | ||||
168 | my $x = $it->next(); | ||||
169 | print "$x, "; | ||||
170 | } | ||||
171 | </verbatim> | ||||
172 | will print | ||||
173 | <verbatim> | ||||
174 | 2, 4 | ||||
175 | </verbatim> | ||||
176 | |||||
177 | =cut | ||||
178 | |||||
179 | # spent 531ms (446+85.1) within Foswiki::ListIterator::next which was called 67905 times, avg 8µs/call:
# 50360 times (345ms+67.4ms) by Foswiki::Iterator::FilterIterator::hasNext at line 72 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 8µs/call
# 17520 times (101ms+17.7ms) by Foswiki::Search::ResultSet::hasNext at line 105 of /var/www/foswikidev/core/lib/Foswiki/Search/ResultSet.pm, avg 7µs/call
# 24 times (96µs+23µs) by Foswiki::deepWebList at line 1657 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 5µs/call
# once (6µs+1µs) by Foswiki::UserMapping::isInGroup at line 428 of /var/www/foswikidev/core/lib/Foswiki/UserMapping.pm | ||||
180 | 67905 | 20.8ms | my $this = shift; | ||
181 | 67905 | 59.5ms | 67905 | 85.1ms | $this->hasNext(); # spent 85.1ms making 67905 calls to Foswiki::ListIterator::hasNext, avg 1µs/call |
182 | 67905 | 30.0ms | my $n = $this->{next}; | ||
183 | 67905 | 21.6ms | $this->{next} = undef; | ||
184 | 67905 | 17.7ms | $n = &{ $this->{process} }($n) if $this->{process}; | ||
185 | 67905 | 277ms | return $n; | ||
186 | } | ||||
187 | |||||
188 | =begin TML | ||||
189 | |||||
190 | ---++ ObjectMethod all() -> @list | ||||
191 | |||||
192 | Exhaust the iterator. Return all remaining elements in the iteration | ||||
193 | as a list. The returned list should be considered to be immutable. | ||||
194 | |||||
195 | This method is cheap if it is called when the cursor is at the first | ||||
196 | element in the iteration, and expensive otherwise, as it requires a list | ||||
197 | copy to be made. | ||||
198 | |||||
199 | =cut | ||||
200 | |||||
201 | # spent 57µs within Foswiki::ListIterator::all which was called 24 times, avg 2µs/call:
# 24 times (57µs+0s) by Foswiki::Store::Rcs::Store::eachWeb at line 611 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm, avg 2µs/call | ||||
202 | 24 | 5µs | my $this = shift; | ||
203 | 24 | 11µs | if ( $this->{index} ) { | ||
204 | my @copy = @{ $this->{list} }; # don't damage the original list | ||||
205 | splice( @copy, 0, $this->{index} ); | ||||
206 | $this->{index} = scalar( @{ $this->{list} } ); | ||||
207 | return @copy; | ||||
208 | } | ||||
209 | else { | ||||
210 | |||||
211 | # At the start (good) | ||||
212 | 24 | 11µs | $this->{index} = scalar( @{ $this->{list} } ); | ||
213 | 24 | 50µs | return @{ $this->{list} }; | ||
214 | } | ||||
215 | } | ||||
216 | |||||
217 | =begin TML | ||||
218 | |||||
219 | ---++ reset() -> $boolean | ||||
220 | |||||
221 | Start at the begining of the list | ||||
222 | <verbatim> | ||||
223 | $it->reset(); | ||||
224 | while ($it->hasNext()) { | ||||
225 | ... | ||||
226 | </verbatim> | ||||
227 | |||||
228 | =cut | ||||
229 | |||||
230 | # spent 206µs within Foswiki::ListIterator::reset which was called 80 times, avg 3µs/call:
# 80 times (206µs+0s) by Foswiki::Iterator::FilterIterator::reset at line 137 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 3µs/call | ||||
231 | 80 | 32µs | my ($this) = @_; | ||
232 | 80 | 34µs | $this->{next} = undef; | ||
233 | 80 | 25µs | $this->{index} = 0; | ||
234 | |||||
235 | 80 | 4.21ms | return 1; | ||
236 | } | ||||
237 | |||||
238 | 1 | 3µs | 1; | ||
239 | __END__ |