Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/ListIterator.pm |
Statements | Executed 66781 statements in 182ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
7851 | 12 | 7 | 109ms | 109ms | hasNext | Foswiki::ListIterator::
3920 | 6 | 5 | 62.6ms | 82.7ms | next | Foswiki::ListIterator::
13 | 9 | 7 | 371µs | 421µs | new | Foswiki::ListIterator::
1 | 1 | 1 | 25µs | 32µs | BEGIN@16 | Foswiki::ListIterator::
1 | 1 | 1 | 16µs | 53µs | BEGIN@22 | Foswiki::ListIterator::
1 | 1 | 1 | 16µs | 34µs | BEGIN@17 | Foswiki::ListIterator::
1 | 1 | 1 | 12µs | 12µs | reset | Foswiki::ListIterator::
1 | 1 | 1 | 9µs | 9µs | BEGIN@19 | Foswiki::ListIterator::
0 | 0 | 0 | 0s | 0s | all | 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 | 45µs | 2 | 39µs | # spent 32µs (25+7) within Foswiki::ListIterator::BEGIN@16 which was called:
# once (25µs+7µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 16 # spent 32µs making 1 call to Foswiki::ListIterator::BEGIN@16
# spent 7µs making 1 call to strict::import |
17 | 2 | 43µs | 2 | 52µs | # spent 34µs (16+18) within Foswiki::ListIterator::BEGIN@17 which was called:
# once (16µs+18µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 17 # spent 34µs making 1 call to Foswiki::ListIterator::BEGIN@17
# spent 18µs making 1 call to warnings::import |
18 | |||||
19 | 2 | 63µs | 1 | 9µs | # spent 9µs within Foswiki::ListIterator::BEGIN@19 which was called:
# once (9µs+0s) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 19 # spent 9µs making 1 call to Foswiki::ListIterator::BEGIN@19 |
20 | 1 | 9µs | our @ISA = ('Foswiki::Iterator'); | ||
21 | |||||
22 | 2 | 956µs | 2 | 90µs | # spent 53µs (16+37) within Foswiki::ListIterator::BEGIN@22 which was called:
# once (16µs+37µs) by Foswiki::Users::TopicUserMapping::BEGIN@35 at line 22 # spent 53µs making 1 call to Foswiki::ListIterator::BEGIN@22
# spent 37µ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 421µs (371+49) within Foswiki::ListIterator::new which was called 13 times, avg 32µs/call:
# 3 times (52µs+10µs) by Foswiki::Users::BaseUserMapping::eachGroupMember at line 291 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/BaseUserMapping.pm, avg 21µs/call
# 2 times (70µs+7µs) by Foswiki::Users::TopicUserMapping::eachGroup at line 719 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 38µs/call
# 2 times (45µs+7µs) by Foswiki::Users::TopicUserMapping::eachGroupMember at line 675 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 26µs/call
# once (45µs+6µs) by Foswiki::Store::VC::Store::eachTopic at line 496 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/VC/Store.pm
# once (45µs+4µs) by Foswiki::Users::HtPasswdUser::fetchUsers at line 141 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/HtPasswdUser.pm
# once (41µs+4µs) by Foswiki::Store::Interfaces::QueryAlgorithm::getWebIterator at line 206 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm
# once (29µs+4µs) by Foswiki::Search::InfoCache::new at line 53 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search/InfoCache.pm
# once (26µs+4µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm:65] at line 45 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm
# once (19µs+3µs) by Foswiki::Users::TopicUserMapping::eachGroupMember at line 624 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm | ||||
35 | 52 | 359µs | my ( $class, $list ) = @_; | ||
36 | |||||
37 | 13 | 49µs | ASSERT( !defined($list) || UNIVERSAL::isa( $list, 'ARRAY' ) ) if DEBUG; # spent 49µs making 13 calls to Assert::ASSERTS_OFF, avg 4µs/call | ||
38 | |||||
39 | my $this = bless( | ||||
40 | { | ||||
41 | list => $list, | ||||
42 | index => 0, | ||||
43 | process => undef, | ||||
44 | filter => undef, | ||||
45 | next => undef, | ||||
46 | }, | ||||
47 | $class | ||||
48 | ); | ||||
49 | return $this; | ||||
50 | } | ||||
51 | |||||
52 | =begin TML | ||||
53 | |||||
54 | ---++ hasNext() -> $boolean | ||||
55 | |||||
56 | Returns false when the iterator is exhausted. | ||||
57 | |||||
58 | <verbatim> | ||||
59 | my $it = new Foswiki::ListIterator(\@list); | ||||
60 | while ($it->hasNext()) { | ||||
61 | ... | ||||
62 | </verbatim> | ||||
63 | |||||
64 | =cut | ||||
65 | |||||
66 | # spent 109ms within Foswiki::ListIterator::hasNext which was called 7851 times, avg 14µs/call:
# 3920 times (20.1ms+0s) by Foswiki::ListIterator::next at line 165, avg 5µs/call
# 3403 times (76.8ms+0s) by Foswiki::Iterator::FilterIterator::hasNext at line 66 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 23µs/call
# 401 times (9.30ms+0s) by Foswiki::Users::TopicUserMapping::_loadMapping at line 1600 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 23µs/call
# 26 times (578µs+0s) by Foswiki::Users::TopicUserMapping::isGroup at line 703 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 22µs/call
# 25 times (581µs+0s) by Foswiki::Iterator::FilterIterator::hasNext at line 64 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 23µs/call
# 25 times (564µs+0s) by Foswiki::UserMapping::isInGroup at line 408 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UserMapping.pm, avg 23µs/call
# 23 times (586µs+0s) by Foswiki::Search::ResultSet::hasNext at line 98 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search/ResultSet.pm, avg 25µs/call
# 22 times (463µs+0s) by Foswiki::AggregateIterator::hasNext at line 70 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/AggregateIterator.pm, avg 21µs/call
# 2 times (60µs+0s) by Foswiki::Users::TopicUserMapping::isGroup at line 701 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 30µs/call
# 2 times (51µs+0s) by Foswiki::UserMapping::isInGroup at line 402 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UserMapping.pm, avg 25µs/call
# once (32µs+0s) by Foswiki::Users::TopicUserMapping::_loadMapping at line 1598 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm
# once (17µs+0s) by Foswiki::Search::formatResults at line 711 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm | ||||
67 | 31404 | 78.1ms | my ($this) = @_; | ||
68 | return 1 | ||||
69 | if defined( $this->{next} ) | ||||
70 | ; #SMELL: this is still wrong if the array element == undef, but at least means zero is an element | ||||
71 | my $n; | ||||
72 | do { | ||||
73 | 7860 | 14.3ms | if ( $this->{list} && $this->{index} < scalar( @{ $this->{list} } ) ) { | ||
74 | $n = $this->{list}->[ $this->{index}++ ]; | ||||
75 | } | ||||
76 | else { | ||||
77 | return 0; | ||||
78 | } | ||||
79 | 3931 | 28.0ms | } while ( $this->{filter} && !&{ $this->{filter} }($n) ); | ||
80 | $this->{next} = $n; | ||||
81 | print STDERR "ListIterator::hasNext -> $this->{index} == $this->{next}\n" | ||||
82 | if Foswiki::Iterator::MONITOR; | ||||
83 | return 1; | ||||
84 | } | ||||
85 | |||||
86 | =begin TML | ||||
87 | |||||
88 | ---++ skip(count) -> $countremaining | ||||
89 | |||||
90 | skip X elements (returns 0 if successful, or number of elements remaining to skip if there are not enough elements to skip) | ||||
91 | skip must set up next as though hasNext was called. | ||||
92 | |||||
93 | =cut | ||||
94 | |||||
95 | sub skip { | ||||
96 | my $this = shift; | ||||
97 | my $count = shift; | ||||
98 | |||||
99 | if ( defined( $this->{next} ) ) { | ||||
100 | $count--; | ||||
101 | } | ||||
102 | |||||
103 | return 0 if ( $count <= 0 ); | ||||
104 | print STDERR | ||||
105 | "--------------------------------------------ListIterator::skip($count) $this->{index}, " | ||||
106 | . scalar( @{ $this->{list} } ) . "\n" | ||||
107 | if Foswiki::Iterator::MONITOR; | ||||
108 | |||||
109 | if ( ( $this->{index} + $count ) >= scalar( @{ $this->{list} } ) ) { | ||||
110 | |||||
111 | #list too small | ||||
112 | $count = ( $this->{index} + $count ) - scalar( @{ $this->{list} } ); | ||||
113 | $this->{index} = 1 + scalar( @{ $this->{list} } ); | ||||
114 | } | ||||
115 | else { | ||||
116 | $this->{index} += $count; | ||||
117 | $count = 0; | ||||
118 | } | ||||
119 | $this->{next} = undef; | ||||
120 | my $hasnext = $this->hasNext(); | ||||
121 | print STDERR | ||||
122 | "--------------------------------------------ListIterator::skip() => $this->{index} $count, $hasnext\n" | ||||
123 | if Foswiki::Iterator::MONITOR; | ||||
124 | |||||
125 | return $count; | ||||
126 | } | ||||
127 | |||||
128 | =begin TML | ||||
129 | |||||
130 | ---++ next() -> $data | ||||
131 | |||||
132 | Return the next entry in the list. | ||||
133 | |||||
134 | The iterator object can be customised to pre- and post-process entries from | ||||
135 | the list before returning them. This is done by setting two fields in the | ||||
136 | iterator object: | ||||
137 | |||||
138 | * ={filter}= can be defined to be a sub that filters each entry. The entry | ||||
139 | will be ignored (next() will not return it) if the filter returns false. | ||||
140 | * ={process}= can be defined to be a sub to process each entry before it | ||||
141 | is returned by next. The value returned from next is the value returned | ||||
142 | by the process function. | ||||
143 | |||||
144 | For example, | ||||
145 | <verbatim> | ||||
146 | my @list = ( 1, 2, 3 ); | ||||
147 | |||||
148 | my $it = new Foswiki::ListIterator(\@list); | ||||
149 | $it->{filter} = sub { return $_[0] != 2 }; | ||||
150 | $it->{process} = sub { return $_[0] + 1 }; | ||||
151 | while ($it->hasNext()) { | ||||
152 | my $x = $it->next(); | ||||
153 | print "$x, "; | ||||
154 | } | ||||
155 | </verbatim> | ||||
156 | will print | ||||
157 | <verbatim> | ||||
158 | 2, 4 | ||||
159 | </verbatim> | ||||
160 | |||||
161 | =cut | ||||
162 | |||||
163 | # spent 82.7ms (62.6+20.1) within Foswiki::ListIterator::next which was called 3920 times, avg 21µs/call:
# 3426 times (54.6ms+17.6ms) by Foswiki::Iterator::FilterIterator::hasNext at line 65 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 21µs/call
# 401 times (6.39ms+2.03ms) by Foswiki::Users::TopicUserMapping::_loadMapping at line 1599 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 21µs/call
# 28 times (436µs+205µs) by Foswiki::Users::TopicUserMapping::isGroup at line 702 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 23µs/call
# 25 times (426µs+127µs) by Foswiki::UserMapping::isInGroup at line 403 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UserMapping.pm, avg 22µs/call
# 22 times (408µs+116µs) by Foswiki::Search::ResultSet::hasNext at line 99 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search/ResultSet.pm, avg 24µs/call
# 18 times (289µs+97µs) by Foswiki::AggregateIterator::hasNext at line 71 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/AggregateIterator.pm, avg 21µs/call | ||||
164 | 23520 | 60.3ms | my $this = shift; | ||
165 | 3920 | 20.1ms | $this->hasNext(); # spent 20.1ms making 3920 calls to Foswiki::ListIterator::hasNext, avg 5µs/call | ||
166 | my $n = $this->{next}; | ||||
167 | $this->{next} = undef; | ||||
168 | $n = &{ $this->{process} }($n) if $this->{process}; | ||||
169 | return $n; | ||||
170 | } | ||||
171 | |||||
172 | =begin TML | ||||
173 | |||||
174 | ---++ ObjectMethod all() -> @list | ||||
175 | |||||
176 | Exhaust the iterator. Return all remaining elements in the iteration | ||||
177 | as a list. The returned list should be considered to be immutable. | ||||
178 | |||||
179 | This method is cheap if it is called when the cursor is at the first | ||||
180 | element in the iteration, and expensive otherwise, as it requires a list | ||||
181 | copy to be made. | ||||
182 | |||||
183 | =cut | ||||
184 | |||||
185 | sub all { | ||||
186 | my $this = shift; | ||||
187 | if ( $this->{index} ) { | ||||
188 | my @copy = @{ $this->{list} }; # don't damage the original list | ||||
189 | splice( @copy, 0, $this->{index} ); | ||||
190 | $this->{index} = scalar( @{ $this->{list} } ); | ||||
191 | return @copy; | ||||
192 | } | ||||
193 | else { | ||||
194 | |||||
195 | # At the start (good) | ||||
196 | $this->{index} = scalar( @{ $this->{list} } ); | ||||
197 | return @{ $this->{list} }; | ||||
198 | } | ||||
199 | } | ||||
200 | |||||
201 | =begin TML | ||||
202 | |||||
203 | ---++ reset() -> $boolean | ||||
204 | |||||
205 | Start at the begining of the list | ||||
206 | <verbatim> | ||||
207 | $it->reset(); | ||||
208 | while ($it->hasNext()) { | ||||
209 | ... | ||||
210 | </verbatim> | ||||
211 | |||||
212 | =cut | ||||
213 | |||||
214 | # spent 12µs within Foswiki::ListIterator::reset which was called:
# once (12µs+0s) by Foswiki::Iterator::FilterIterator::reset at line 127 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Iterator/FilterIterator.pm | ||||
215 | 4 | 16µs | my ($this) = @_; | ||
216 | $this->{next} = undef; | ||||
217 | $this->{index} = 0; | ||||
218 | |||||
219 | return 1; | ||||
220 | } | ||||
221 | |||||
222 | 1 | 6µs | 1; | ||
223 | __END__ |