File Coverage

lib/Class/STL/Iterators.pm
Criterion Covered Total %
statement 192 198 96.9
branch 50 68 73.5
condition 32 72 44.4
subroutine 57 58 98.2
pod n/a
total 331 396 83.5


line stmt bran cond sub pod time code
1             # vim:ts=4 sw=4
2             # ----------------------------------------------------------------------------------------------------
3             # Name : Class::STL::Iterators.pm
4             # Created : 22 February 2006
5             # Author : Mario Gaffiero (gaffie)
6             #
7             # Copyright 2006-2007 Mario Gaffiero.
8             #
9             # This file is part of Class::STL::Containers(TM).
10             #
11             # Class::STL::Containers is free software; you can redistribute it and/or modify
12             # it under the terms of the GNU General Public License as published by
13             # the Free Software Foundation; version 2 of the License.
14             #
15             # Class::STL::Containers is distributed in the hope that it will be useful,
16             # but WITHOUT ANY WARRANTY; without even the implied warranty of
17             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18             # GNU General Public License for more details.
19             #
20             # You should have received a copy of the GNU General Public License
21             # along with Class::STL::Containers; if not, write to the Free Software
22             # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23             # ----------------------------------------------------------------------------------------------------
24             # Modification History
25             # When Version Who What
26             # ----------------------------------------------------------------------------------------------------
27             # TO DO:
28             # ----------------------------------------------------------------------------------------------------
29             package Class::STL::Iterators;
30             require 5.005_62;
31 7     7   41 use strict;
  7         16  
  7         187  
32 7     7   32 use warnings;
  7         12  
  7         192  
33 7     7   31 use vars qw( $VERSION $BUILD @ISA @EXPORT_OK %EXPORT_TAGS );
  7         11  
  7         855  
34             require Exporter;
35             @ISA = 'Exporter';
36             my @export_names = qw(
37             iterator
38             bidirectional_iterator
39             reverse_iterator
40             forward_iterator
41             distance
42             advance
43             back_insert_iterator
44             front_insert_iterator
45             back_inserter
46             front_inserter
47             insert_iterator
48             inserter
49             );
50             @EXPORT_OK = (@export_names);
51             %EXPORT_TAGS = ( all => [@export_names] );
52             $VERSION = '0.18';
53             $BUILD = 'Thursday April 27 23:08:34 GMT 2006';
54             # ----------------------------------------------------------------------------------------------------
55             {
56             package Class::STL::Iterators;
57 7     7   42 use vars qw( $AUTOLOAD );
  7         12  
  7         1812  
58             sub AUTOLOAD
59             {
60 415     415   2059 (my $func = $AUTOLOAD) =~ s/.*:://;
61 415 100       9230 return Class::STL::Iterators::BiDirectional->new(@_) if ($func eq 'iterator');
62 63 50       196 return Class::STL::Iterators::BiDirectional->new(@_) if ($func eq 'bidirectional_iterator');
63 63 100       228 return Class::STL::Iterators::Forward->new(@_) if ($func eq 'forward_iterator');
64 62 100       305 return Class::STL::Iterators::Reverse->new(@_) if ($func eq 'reverse_iterator');
65 56 100       278 return Class::STL::Iterators::Abstract::distance(@_) if ($func eq 'distance');
66 11 100       25 return Class::STL::Iterators::Abstract::advance(@_) if ($func eq 'advance');
67 9 50       18 return Class::STL::Iterators::BackInsertIterator->new(@_) if ($func eq 'back_insert_iterator');
68 9 50       14 return Class::STL::Iterators::FrontInsertIterator->new(@_) if ($func eq 'front_insert_iterator');
69 9 100       17 return Class::STL::Iterators::Abstract::back_inserter(@_) if ($func eq 'back_inserter');
70 6 100       30 return Class::STL::Iterators::Abstract::front_inserter(@_) if ($func eq 'front_inserter');
71 2 50       6 return Class::STL::Iterators::InsertIterator->new(@_) if ($func eq 'insert_iterator');
72 2 50       9 return Class::STL::Iterators::Abstract::inserter(@_) if ($func eq 'inserter');
73             }
74             }
75             # ----------------------------------------------------------------------------------------------------
76             {
77             package Class::STL::Iterators::Abstract;
78 7     7   57 use base qw(Class::STL::Element);
  7         13  
  7         1029  
79 7     7   43 use Carp qw(confess);
  7         12  
  7         517  
80 7         44 use overload '++' => 'next', '--' => 'prev', '=' => 'clone', 'bool' => '_bool',
81             '+' => 'advance', '+=' => 'advance', '-' => 'retreat', '-=' => 'retreat',
82 7     7   40 '==' => 'eq', '!=' => 'ne', '>' => 'gt', '<' => 'lt', '>=' => 'ge', '<=' => 'le', '<=>' => 'cmp';
  7         11  
83 7         64 use Class::STL::ClassMembers qw(p_container),
84 7     7   1894 Class::STL::ClassMembers::DataMember->new(name => 'arr_idx', default => -1);
  7         24  
85 7     7   40 use Class::STL::ClassMembers::Constructor;
  7         15  
  7         45  
86             sub p_element
87             {
88 2526     2526   3712 my $self = shift;
89             return $self->arr_idx() < 0 || $self->arr_idx() >= $self->p_container()->size()
90             ? 0
91 2526 50 33     48146 : ${$self->p_container()->data()}[$self->arr_idx()]
  2526         48623  
92             }
93             sub idx_check # (void)
94             {
95 5212     5212   6564 my $self = shift;
96 5212 100       101774 $self->arr_idx($self->p_container()->size()-1) if ($self->arr_idx() >= $self->p_container()->size());
97 5212 100       101249 $self->arr_idx(-1) if ($self->arr_idx() < 0);
98 5212         8586 return;
99             }
100             sub at_end # (void)
101             {
102 2730     2730   4799 my $self = shift;
103 2730         5441 $self->idx_check();
104 2730 100       51588 return $self->arr_idx() == -1 ? 1 : 0;
105             }
106             sub prev # (void)
107             {
108 158     158   259 my $self = shift;
109 158         354 $self->idx_check();
110 158 100       2647 return $self->last() if ($self->arr_idx() == -1);
111 89 100 66     1610 (!$self->p_container()->size() || $self->arr_idx() == 0)
112             ? $self->arr_idx(-1)
113             : $self->arr_idx($self->arr_idx() -1);
114 89         284 return $self; # iterator
115             }
116             sub next # (void)
117             {
118 1866     1866   3185 my $self = shift;
119 1866         4252 $self->idx_check();
120 1866 100       37161 return $self if ($self->arr_idx() == -1);
121 1744 100 66     32662 (!$self->p_container()->size() || $self->arr_idx()+1 >= $self->p_container()->size())
122             ? $self->arr_idx(-1)
123             : $self->arr_idx($self->arr_idx() +1);
124 1744         5770 return $self; # iterator
125             }
126             sub first # (void)
127             {
128 285     285   548 my $self = shift;
129 285         777 $self->idx_check();
130 285 100       5401 (!$self->p_container()->size())
131             ? $self->arr_idx(-1)
132             : $self->arr_idx(0);
133 285         1500 return $self; # iterator
134             }
135             sub last # (void)
136             {
137 173     173   310 my $self = shift;
138 173         443 $self->idx_check();
139 173 100       3058 (!$self->p_container()->size())
140             ? $self->arr_idx(-1)
141             : $self->arr_idx($self->p_container()->size()-1);
142 173         950 return $self; # iterator
143             }
144             sub front_inserter # (container) -- static function
145             {
146 4     4   6 my $c = shift;
147 4 50 33     33 confess "A front_insert_iterator can only be used with a container that defines the push_front() member function\n"
      33        
148             unless (ref($c) && $c->isa('Class::STL::Containers::Abstract') && $c->can('push_front'));
149 4         78 return Class::STL::Iterators::FrontInsertIterator->new(p_container => $c);
150             }
151             sub back_inserter # (container) -- static function
152             {
153 3     3   5 my $c = shift;
154 3 50 33     32 confess "A back_insert_iterator can only be used with a container that defines the push_back() member function\n"
      33        
155             unless (ref($c) && $c->isa('Class::STL::Containers::Abstract') && $c->can('push_back'));
156 3         62 return Class::STL::Iterators::BackInsertIterator->new(p_container => $c);
157             }
158             sub inserter # (container, iterator) -- static function
159             {
160 2     2   4 my $c = shift;
161 2         2 my $i = shift;
162 2 50 33     19 confess "Usage:inserter(container, iterator)"
      33        
      33        
163             unless (ref($c) && $c->isa('Class::STL::Containers::Abstract')
164             && ref($i) && $i->isa('Class::STL::Iterators::Abstract'));
165 2         33 return Class::STL::Iterators::InsertIterator->new(p_container => $c, arr_idx => $i->arr_idx());
166             }
167             sub distance # (iterator, iterator) -- static function
168             {
169 45     45   105 my $iter_start = shift;
170 45         76 my $iter_finish = shift;
171 45 50 33     1763 confess "@{[ __PACKAGE__ ]}::distance usage:\ndistance( iterator-start, iterator-finish );"
  0   33     0  
      33        
      33        
      33        
      33        
172             unless (
173             defined($iter_start) && ref($iter_start) && $iter_start->isa('Class::STL::Iterators::Abstract')
174             && defined($iter_finish) && ref($iter_finish) && $iter_finish->isa('Class::STL::Iterators::Abstract')
175             && $iter_start->p_container() == $iter_finish->p_container()
176             );
177 45 50 33     177 return -1 if ($iter_start->at_end() && $iter_finish->at_end());
178 45 50 33     140 return -1 if ($iter_start->at_end() || $iter_start->gt($iter_finish));
179 45 50       156 return $iter_finish->p_container()->size()-1 - $iter_start->arr_idx() if ($iter_finish->at_end());
180 45         894 return $iter_finish->arr_idx() - $iter_start->arr_idx();
181             }
182             sub advance # (size) -- static function
183             {
184 103     103   164 my $iter = shift;
185 103         135 my $size = shift;
186 103 100       258 if ($size >= 0)
187             {
188 18         65 for (my $i=0; $i<$size; ++$i) { $iter->next(); }
  29         68  
189             }
190             else
191             {
192 85         173 for (my $i=$size; $i!=0; ++$i) { $iter->prev(); }
  87         180  
193             }
194 103         431 return $iter;
195             }
196             sub retreat # (size) -- static function
197             {
198 84     84   139 my $iter = shift;
199 84         106 my $size = shift;
200 84         219 return $iter->advance(-$size);
201 0         0 return $iter;
202             }
203             sub eq # (element)
204             {
205 99     99   213 my $self = shift;
206 99         136 my $other = shift;
207             return
208             #? $self->p_container() == $other->p_container()
209 99         2019 $self->arr_idx() == $other->arr_idx();
210             }
211             sub ne # (element)
212             {
213 99     99   196 my $self = shift;
214 99 100       237 return $self->eq(shift) ? 0 : 1;
215             }
216             sub gt # (element)
217             {
218 49     49   104 my $self = shift;
219 49         92 my $other = shift;
220 49   66     112 return !$self->at_end() && !$other->at_end()
221             #? && $self->p_container() == $other->p_container()
222             && $self->arr_idx() > $other->arr_idx();
223             }
224             sub ge # (element)
225             {
226 40     40   64 my $self = shift;
227 40         51 my $other = shift;
228 40   100     81 return !$self->at_end() && !$other->at_end()
229             #? && $self->p_container() == $other->p_container()
230             && $self->arr_idx() >= $other->arr_idx();
231             }
232             sub lt # (element)
233             {
234 11     11   23 my $self = shift;
235 11         18 my $other = shift;
236 11   66     38 return !$self->at_end() && !$other->at_end()
237             #? && $self->p_container() == $other->p_container()
238             && $self->arr_idx() < $other->arr_idx();
239             }
240             sub le # (element)
241             {
242 542     542   978 my $self = shift;
243 542         737 my $other = shift;
244 542   100     1130 return !$self->at_end() && !$other->at_end()
245             #? && $self->p_container() == $other->p_container() # -- don't want overloaded == !!
246             && $self->arr_idx() <= $other->arr_idx();
247             }
248             sub cmp # (element)
249             {
250 0     0   0 my $self = shift;
251 0         0 my $other = shift;
252 0 0       0 return $self->eq($other) ? 0 : $self->lt($other) ? -1 : 1;
    0          
253             }
254             sub _bool
255             {
256 42     42   108 my $self = shift;
257 42         156 return $self;
258             }
259             }
260             # ----------------------------------------------------------------------------------------------------
261             {
262             package Class::STL::Iterators::BiDirectional;
263 7     7   53 use base qw(Class::STL::Iterators::Abstract);
  7         14  
  7         2082  
264 7     7   47 use Class::STL::ClassMembers;
  7         15  
  7         30  
265 7     7   42 use Class::STL::ClassMembers::Constructor;
  7         15  
  7         31  
266             }
267             # ----------------------------------------------------------------------------------------------------
268             {
269             package Class::STL::Iterators::Forward;
270 7     7   40 use base qw(Class::STL::Iterators::BiDirectional);
  7         13  
  7         1755  
271 7     7   48 use Class::STL::ClassMembers;
  7         15  
  7         28  
272 7     7   37 use Class::STL::ClassMembers::Constructor;
  7         15  
  7         29  
273 7     7   2956 use Class::STL::ClassMembers::Disable qw(prev);
  7         18  
  7         27  
274 7     7   41 use Class::STL::ClassMembers::Disable qw(last);
  7         13  
  7         24  
275             }
276             # ----------------------------------------------------------------------------------------------------
277             {
278             package Class::STL::Iterators::Reverse;
279 7     7   41 use base qw(Class::STL::Iterators::BiDirectional);
  7         13  
  7         1703  
280 7     7   50 use Class::STL::ClassMembers;
  7         13  
  7         29  
281 7     7   39 use Class::STL::ClassMembers::Constructor;
  7         12  
  7         49  
282             sub last # (void)
283             {
284 3     3   4 my $self = shift;
285 3         15 return $self->SUPER::first(); # iterator
286             }
287             sub first # (void)
288             {
289 3     3   6 my $self = shift;
290 3         11 return $self->SUPER::last(); # iterator
291             }
292             sub next # (void)
293             {
294 6     6   8 my $self = shift;
295 6         12 return $self->SUPER::prev(); # iterator
296             }
297             sub prev # (void)
298             {
299 6     6   9 my $self = shift;
300 6         13 return $self->SUPER::next(); # iterator
301             }
302             }
303             # ----------------------------------------------------------------------------------------------------
304             {
305             package Class::STL::Iterators::BackInsertIterator;
306 7     7   42 use base qw(Class::STL::Iterators::Abstract);
  7         28  
  7         1913  
307 7     7   46 use Class::STL::ClassMembers;
  7         15  
  7         28  
308 7     7   38 use Class::STL::ClassMembers::Constructor;
  7         15  
  7         27  
309             sub assign # (element)
310             {
311 15     15   18 my $self = shift;
312 15         223 $self->p_container()->push_back(@_);
313             }
314             }
315             # ----------------------------------------------------------------------------------------------------
316             {
317             package Class::STL::Iterators::FrontInsertIterator;
318 7     7   41 use base qw(Class::STL::Iterators::Abstract);
  7         13  
  7         1484  
319 7     7   56 use Class::STL::ClassMembers;
  7         13  
  7         175  
320 7     7   36 use Class::STL::ClassMembers::Constructor;
  7         13  
  7         26  
321             sub assign # (element)
322             {
323 23     23   35 my $self = shift;
324 23         357 $self->p_container()->push_front(@_);
325             }
326             }
327             # ----------------------------------------------------------------------------------------------------
328             {
329             package Class::STL::Iterators::InsertIterator;
330 7     7   37 use base qw(Class::STL::Iterators::Abstract);
  7         12  
  7         1471  
331 7     7   47 use Class::STL::ClassMembers;
  7         12  
  7         29  
332 7     7   36 use Class::STL::ClassMembers::Constructor;
  7         12  
  7         25  
333             sub assign # (element)
334             {
335 5     5   7 my $self = shift;
336 5 50 33     73 if (!$self->p_container()->size() || $self->at_end())
337             {
338 0         0 $self->p_container()->push(@_);
339             }
340             else
341             {
342 5   33     8 CORE::splice(@{$self->p_container()->data()}, $self->arr_idx(), 0,
  5         76  
343             grep(ref && $_->isa('Class::STL::Element'), @_));
344             }
345 5         11 return $self->next();
346             }
347             }
348             # ----------------------------------------------------------------------------------------------------
349             1;