Filename | /var/www/foswiki11/lib/Foswiki/ListIterator.pm |
Statements | Executed 992877 statements in 1.38s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
70722 | 5 | 5 | 484ms | 574ms | next | Foswiki::ListIterator::
141616 | 10 | 6 | 420ms | 420ms | hasNext | Foswiki::ListIterator::
235 | 7 | 4 | 3.40ms | 3.96ms | new | Foswiki::ListIterator::
100 | 1 | 1 | 310µs | 310µs | all | Foswiki::ListIterator::
81 | 1 | 1 | 271µs | 271µs | reset | Foswiki::ListIterator::
1 | 1 | 1 | 13µs | 26µs | BEGIN@16 | Foswiki::ListIterator::
1 | 1 | 1 | 12µs | 17µs | BEGIN@17 | Foswiki::ListIterator::
1 | 1 | 1 | 8µs | 21µs | BEGIN@22 | 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 | 29µ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 | 25µs | 2 | 22µs | # spent 17µs (12+5) within Foswiki::ListIterator::BEGIN@17 which was called:
# once (12µs+5µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 17 # spent 17µs making 1 call to Foswiki::ListIterator::BEGIN@17
# spent 5µs making 1 call to warnings::import |
18 | |||||
19 | 2 | 32µ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 | 537µs | 2 | 33µs | # spent 21µs (8+12) within Foswiki::ListIterator::BEGIN@22 which was called:
# once (8µs+12µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 22 # spent 21µs making 1 call to Foswiki::ListIterator::BEGIN@22
# spent 12µs making 1 call to Assert::import |
23 | |||||
24 | =begin TML | ||||
25 | |||||
26 | ---++ new(\@list) | ||||
27 | |||||
28 | Create a new iterator over the given list. Designed primarily for operations | ||||
29 | over fully defined lists of object references. The list is not damaged in | ||||
30 | any way. | ||||
31 | |||||
32 | =cut | ||||
33 | |||||
34 | # spent 3.96ms (3.40+568µs) within Foswiki::ListIterator::new which was called 235 times, avg 17µs/call:
# 102 times (992µs+119µs) by Foswiki::Store::VC::Store::eachWeb at line 442 of /var/www/foswiki11/lib/Foswiki/Store/VC/Store.pm, avg 11µs/call
# 81 times (1.84ms+381µs) by Foswiki::Search::InfoCache::new at line 51 of /var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm, avg 27µs/call
# 41 times (442µs+57µs) by Foswiki::Store::VC::Store::eachTopic at line 418 of /var/www/foswiki11/lib/Foswiki/Store/VC/Store.pm, avg 12µs/call
# 4 times (34µs+4µs) by Foswiki::Users::BaseUserMapping::eachGroupMember at line 293 of /var/www/foswiki11/lib/Foswiki/Users/BaseUserMapping.pm, avg 10µs/call
# 3 times (53µs+3µs) by Foswiki::Users::TopicUserMapping::eachGroupMember at line 729 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 19µs/call
# 3 times (26µs+3µs) by Foswiki::Users::TopicUserMapping::eachGroup at line 773 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 10µs/call
# once (12µs+1µs) by Foswiki::Users::TopicUserMapping::eachGroupMember at line 675 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm | ||||
35 | 235 | 301µs | my ( $class, $list ) = @_; | ||
36 | |||||
37 | 235 | 90µs | $list = [] unless defined $list; | ||
38 | |||||
39 | 235 | 546µs | 235 | 568µs | ASSERT( UNIVERSAL::isa( $list, 'ARRAY' ) ) if DEBUG; # spent 568µs making 235 calls to Assert::ASSERTS_OFF, avg 2µs/call |
40 | |||||
41 | 235 | 1.40ms | my $this = bless( | ||
42 | { | ||||
43 | list => $list, | ||||
44 | index => 0, | ||||
45 | process => undef, | ||||
46 | filter => undef, | ||||
47 | next => undef, | ||||
48 | }, | ||||
49 | $class | ||||
50 | ); | ||||
51 | 235 | 917µs | return $this; | ||
52 | } | ||||
53 | |||||
54 | =begin TML | ||||
55 | |||||
56 | ---++ hasNext() -> $boolean | ||||
57 | |||||
58 | Returns false when the iterator is exhausted. | ||||
59 | |||||
60 | <verbatim> | ||||
61 | my $it = new Foswiki::ListIterator(\@list); | ||||
62 | while ($it->hasNext()) { | ||||
63 | ... | ||||
64 | </verbatim> | ||||
65 | |||||
66 | =cut | ||||
67 | |||||
68 | # spent 420ms within Foswiki::ListIterator::hasNext which was called 141616 times, avg 3µs/call:
# 70722 times (89.5ms+0s) by Foswiki::ListIterator::next at line 171, avg 1µs/call
# 46206 times (224ms+0s) by Foswiki::Iterator::FilterIterator::hasNext at line 48 of /var/www/foswiki11/lib/Foswiki/Iterator/FilterIterator.pm, avg 5µs/call
# 17686 times (74.3ms+0s) by Foswiki::Search::ResultSet::hasNext at line 93 of /var/www/foswiki11/lib/Foswiki/Search/ResultSet.pm, avg 4µs/call
# 6358 times (28.3ms+0s) by Foswiki::Iterator::FilterIterator::hasNext at line 50 of /var/www/foswiki11/lib/Foswiki/Iterator/FilterIterator.pm, avg 4µs/call
# 301 times (1.26ms+0s) by Foswiki::UserMapping::isInGroup at line 426 of /var/www/foswiki11/lib/Foswiki/UserMapping.pm, avg 4µs/call
# 228 times (830µs+0s) by Foswiki::Users::TopicUserMapping::isGroup at line 757 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 4µs/call
# 100 times (891µs+0s) by Foswiki::deepWebList at line 1575 of /var/www/foswiki11/lib/Foswiki.pm, avg 9µs/call
# 10 times (55µs+0s) by Foswiki::UserMapping::isInGroup at line 420 of /var/www/foswiki11/lib/Foswiki/UserMapping.pm, avg 6µs/call
# 3 times (16µs+0s) by Foswiki::Users::TopicUserMapping::isGroup at line 755 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 5µs/call
# 2 times (19µs+0s) by Foswiki::deepWebList at line 1571 of /var/www/foswiki11/lib/Foswiki.pm, avg 10µs/call | ||||
69 | 141616 | 53.4ms | my ($this) = @_; | ||
70 | 141616 | 318ms | return 1 | ||
71 | if defined( $this->{next} ) | ||||
72 | ; #SMELL: this is still wrong if the array element == undef, but at least means zero is an element | ||||
73 | 70894 | 7.94ms | my $n; | ||
74 | do { | ||||
75 | if ( $this->{list} && $this->{index} < scalar( @{ $this->{list} } ) ) { | ||||
76 | $n = $this->{list}->[ $this->{index}++ ]; | ||||
77 | } | ||||
78 | else { | ||||
79 | 172 | 796µs | return 0; | ||
80 | } | ||||
81 | 70894 | 168ms | } while ( $this->{filter} && !&{ $this->{filter} }($n) ); | ||
82 | 70722 | 24.2ms | $this->{next} = $n; | ||
83 | print STDERR "ListIterator::hasNext -> $this->{index} == $this->{next}\n" | ||||
84 | if Foswiki::Iterator::MONITOR; | ||||
85 | 70722 | 361ms | return 1; | ||
86 | } | ||||
87 | |||||
88 | =begin TML | ||||
89 | |||||
90 | ---++ skip(count) -> $countremaining | ||||
91 | |||||
92 | skip X elements (returns 0 if successful, or number of elements remaining to skip if there are not enough elements to skip) | ||||
93 | skip must set up next as though hasNext was called. | ||||
94 | |||||
95 | =cut | ||||
96 | |||||
97 | sub skip { | ||||
98 | my $this = shift; | ||||
99 | my $count = shift; | ||||
100 | |||||
101 | if ( defined( $this->{next} ) ) { | ||||
102 | $count--; | ||||
103 | } | ||||
104 | |||||
105 | $count ||= 0; | ||||
106 | |||||
107 | return 0 if ( $count <= 0 ); | ||||
108 | print STDERR | ||||
109 | "--------------------------------------------ListIterator::skip($count) $this->{index}, " | ||||
110 | . scalar( @{ $this->{list} } ) . "\n" | ||||
111 | if Foswiki::Iterator::MONITOR; | ||||
112 | |||||
113 | my $length = scalar( @{ $this->{list} } ); | ||||
114 | |||||
115 | if ( ( $this->{index} + $count ) >= $length ) { | ||||
116 | |||||
117 | #list too small | ||||
118 | $count = $this->{index} + $count - $length; | ||||
119 | $this->{index} = 1 + $length; | ||||
120 | } | ||||
121 | else { | ||||
122 | $this->{index} += $count; | ||||
123 | $count = 0; | ||||
124 | } | ||||
125 | $this->{next} = undef; | ||||
126 | my $hasnext = $this->hasNext(); | ||||
127 | print STDERR | ||||
128 | "--------------------------------------------ListIterator::skip() => $this->{index} $count, $hasnext\n" | ||||
129 | if Foswiki::Iterator::MONITOR; | ||||
130 | |||||
131 | return $count; | ||||
132 | } | ||||
133 | |||||
134 | =begin TML | ||||
135 | |||||
136 | ---++ next() -> $data | ||||
137 | |||||
138 | Return the next entry in the list. | ||||
139 | |||||
140 | The iterator object can be customised to pre- and post-process entries from | ||||
141 | the list before returning them. This is done by setting two fields in the | ||||
142 | iterator object: | ||||
143 | |||||
144 | * ={filter}= can be defined to be a sub that filters each entry. The entry | ||||
145 | will be ignored (next() will not return it) if the filter returns false. | ||||
146 | * ={process}= can be defined to be a sub to process each entry before it | ||||
147 | is returned by next. The value returned from next is the value returned | ||||
148 | by the process function. | ||||
149 | |||||
150 | For example, | ||||
151 | <verbatim> | ||||
152 | my @list = ( 1, 2, 3 ); | ||||
153 | |||||
154 | my $it = new Foswiki::ListIterator(\@list); | ||||
155 | $it->{filter} = sub { return $_[0] != 2 }; | ||||
156 | $it->{process} = sub { return $_[0] + 1 }; | ||||
157 | while ($it->hasNext()) { | ||||
158 | my $x = $it->next(); | ||||
159 | print "$x, "; | ||||
160 | } | ||||
161 | </verbatim> | ||||
162 | will print | ||||
163 | <verbatim> | ||||
164 | 2, 4 | ||||
165 | </verbatim> | ||||
166 | |||||
167 | =cut | ||||
168 | |||||
169 | # spent 574ms (484+89.5) within Foswiki::ListIterator::next which was called 70722 times, avg 8µs/call:
# 52483 times (377ms+68.2ms) by Foswiki::Iterator::FilterIterator::hasNext at line 49 of /var/www/foswiki11/lib/Foswiki/Iterator/FilterIterator.pm, avg 8µs/call
# 17605 times (104ms+20.5ms) by Foswiki::Search::ResultSet::hasNext at line 93 of /var/www/foswiki11/lib/Foswiki/Search/ResultSet.pm, avg 7µs/call
# 303 times (1.50ms+376µs) by Foswiki::UserMapping::isInGroup at line 421 of /var/www/foswiki11/lib/Foswiki/UserMapping.pm, avg 6µs/call
# 231 times (1.01ms+261µs) by Foswiki::Users::TopicUserMapping::isGroup at line 756 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 5µs/call
# 100 times (767µs+179µs) by Foswiki::deepWebList at line 1574 of /var/www/foswiki11/lib/Foswiki.pm, avg 9µs/call | ||||
170 | 70722 | 19.6ms | my $this = shift; | ||
171 | 70722 | 62.9ms | 70722 | 89.5ms | $this->hasNext(); # spent 89.5ms making 70722 calls to Foswiki::ListIterator::hasNext, avg 1µs/call |
172 | 70722 | 33.3ms | my $n = $this->{next}; | ||
173 | 70722 | 24.5ms | $this->{next} = undef; | ||
174 | 70722 | 19.2ms | $n = &{ $this->{process} }($n) if $this->{process}; | ||
175 | 70722 | 281ms | return $n; | ||
176 | } | ||||
177 | |||||
178 | =begin TML | ||||
179 | |||||
180 | ---++ ObjectMethod all() -> @list | ||||
181 | |||||
182 | Exhaust the iterator. Return all remaining elements in the iteration | ||||
183 | as a list. The returned list should be considered to be immutable. | ||||
184 | |||||
185 | This method is cheap if it is called when the cursor is at the first | ||||
186 | element in the iteration, and expensive otherwise, as it requires a list | ||||
187 | copy to be made. | ||||
188 | |||||
189 | =cut | ||||
190 | |||||
191 | # spent 310µs within Foswiki::ListIterator::all which was called 100 times, avg 3µs/call:
# 100 times (310µs+0s) by Foswiki::Store::VC::Store::eachWeb at line 436 of /var/www/foswiki11/lib/Foswiki/Store/VC/Store.pm, avg 3µs/call | ||||
192 | 100 | 26µs | my $this = shift; | ||
193 | 100 | 60µs | if ( $this->{index} ) { | ||
194 | my @copy = @{ $this->{list} }; # don't damage the original list | ||||
195 | splice( @copy, 0, $this->{index} ); | ||||
196 | $this->{index} = scalar( @{ $this->{list} } ); | ||||
197 | return @copy; | ||||
198 | } | ||||
199 | else { | ||||
200 | |||||
201 | # At the start (good) | ||||
202 | 100 | 59µs | $this->{index} = scalar( @{ $this->{list} } ); | ||
203 | 100 | 261µs | return @{ $this->{list} }; | ||
204 | } | ||||
205 | } | ||||
206 | |||||
207 | =begin TML | ||||
208 | |||||
209 | ---++ reset() -> $boolean | ||||
210 | |||||
211 | Start at the begining of the list | ||||
212 | <verbatim> | ||||
213 | $it->reset(); | ||||
214 | while ($it->hasNext()) { | ||||
215 | ... | ||||
216 | </verbatim> | ||||
217 | |||||
218 | =cut | ||||
219 | |||||
220 | # spent 271µs within Foswiki::ListIterator::reset which was called 81 times, avg 3µs/call:
# 81 times (271µs+0s) by Foswiki::Iterator::FilterIterator::reset at line 70 of /var/www/foswiki11/lib/Foswiki/Iterator/FilterIterator.pm, avg 3µs/call | ||||
221 | 81 | 39µs | my ($this) = @_; | ||
222 | 81 | 37µs | $this->{next} = undef; | ||
223 | 81 | 30µs | $this->{index} = 0; | ||
224 | |||||
225 | 81 | 228µs | return 1; | ||
226 | } | ||||
227 | |||||
228 | 1 | 3µs | 1; | ||
229 | __END__ |