File Coverage

lib/Class/STL/Iterators.pm
Criterion Covered Total %
statement 90 201 44.7
branch 0 68 0.0
condition 0 72 0.0
subroutine 30 59 50.8
pod n/a
total 120 400 30.0


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   38 use strict;
  7         13  
  7         261  
32 7     7   37 use warnings;
  7         11  
  7         254  
33 7     7   34 use vars qw( $VERSION $BUILD @EXPORT_OK %EXPORT_TAGS );
  7         13  
  7         480  
34 7     7   45 use Exporter;
  7         15  
  7         863  
35             my @export_names = qw(
36             iterator
37             bidirectional_iterator
38             reverse_iterator
39             forward_iterator
40             distance
41             advance
42             back_insert_iterator
43             front_insert_iterator
44             back_inserter
45             front_inserter
46             insert_iterator
47             inserter
48             );
49             @EXPORT_OK = (@export_names);
50             %EXPORT_TAGS = ( all => [@export_names] );
51             $VERSION = '0.18';
52             $BUILD = 'Thursday April 27 23:08:34 GMT 2006';
53             # ----------------------------------------------------------------------------------------------------
54             {
55             package Class::STL::Iterators;
56 7     7   51 use vars qw( $AUTOLOAD );
  7         34  
  7         5546  
57             sub AUTOLOAD
58             {
59 0     0     (my $func = $AUTOLOAD) =~ s/.*:://;
60 0 0         return Class::STL::Iterators::BiDirectional->new(@_) if ($func eq 'iterator');
61 0 0         return Class::STL::Iterators::BiDirectional->new(@_) if ($func eq 'bidirectional_iterator');
62 0 0         return Class::STL::Iterators::Forward->new(@_) if ($func eq 'forward_iterator');
63 0 0         return Class::STL::Iterators::Reverse->new(@_) if ($func eq 'reverse_iterator');
64 0 0         return Class::STL::Iterators::Abstract::distance(@_) if ($func eq 'distance');
65 0 0         return Class::STL::Iterators::Abstract::advance(@_) if ($func eq 'advance');
66 0 0         return Class::STL::Iterators::BackInsertIterator->new(@_) if ($func eq 'back_insert_iterator');
67 0 0         return Class::STL::Iterators::FrontInsertIterator->new(@_) if ($func eq 'front_insert_iterator');
68 0 0         return Class::STL::Iterators::Abstract::back_inserter(@_) if ($func eq 'back_inserter');
69 0 0         return Class::STL::Iterators::Abstract::front_inserter(@_) if ($func eq 'front_inserter');
70 0 0         return Class::STL::Iterators::InsertIterator->new(@_) if ($func eq 'insert_iterator');
71 0 0         return Class::STL::Iterators::Abstract::inserter(@_) if ($func eq 'inserter');
72             }
73             }
74             # ----------------------------------------------------------------------------------------------------
75             {
76             package Class::STL::Iterators::Abstract;
77 7     7   106 use base qw(Class::STL::Element);
  7         29  
  7         1035  
78 7     7   39 use Carp qw(confess);
  7         34  
  7         649  
79 7         57 use overload '++' => 'next', '--' => 'prev', '=' => 'clone', 'bool' => '_bool',
80             '+' => 'advance', '+=' => 'advance', '-' => 'retreat', '-=' => 'retreat',
81 7     7   42 '==' => 'eq', '!=' => 'ne', '>' => 'gt', '<' => 'lt', '>=' => 'ge', '<=' => 'le', '<=>' => 'cmp';
  7         13  
82 7         156 use Class::STL::ClassMembers qw(p_container),
83 7     7   1949 Class::STL::ClassMembers::DataMember->new(name => 'arr_idx', default => -1);
  7         12  
84 7     7   181 use Class::STL::ClassMembers::Constructor;
  7         12  
  7         71  
85             sub p_element
86             {
87 0     0     my $self = shift;
88 0           return $self->arr_idx() < 0 || $self->arr_idx() >= $self->p_container()->size()
89             ? 0
90 0 0 0       : ${$self->p_container()->data()}[$self->arr_idx()]
91             }
92             sub idx_check # (void)
93             {
94 0     0     my $self = shift;
95 0 0         $self->arr_idx($self->p_container()->size()-1) if ($self->arr_idx() >= $self->p_container()->size());
96 0 0         $self->arr_idx(-1) if ($self->arr_idx() < 0);
97 0           return;
98             }
99             sub at_end # (void)
100             {
101 0     0     my $self = shift;
102 0           $self->idx_check();
103 0 0         return $self->arr_idx() == -1 ? 1 : 0;
104             }
105             sub prev # (void)
106             {
107 0     0     my $self = shift;
108 0           $self->idx_check();
109 0 0         return $self->last() if ($self->arr_idx() == -1);
110 0 0 0       (!$self->p_container()->size() || $self->arr_idx() == 0)
111             ? $self->arr_idx(-1)
112             : $self->arr_idx($self->arr_idx() -1);
113 0           return $self; # iterator
114             }
115             sub next # (void)
116             {
117 0     0     my $self = shift;
118 0           $self->idx_check();
119 0 0         return $self if ($self->arr_idx() == -1);
120 0 0 0       (!$self->p_container()->size() || $self->arr_idx()+1 >= $self->p_container()->size())
121             ? $self->arr_idx(-1)
122             : $self->arr_idx($self->arr_idx() +1);
123 0           return $self; # iterator
124             }
125             sub first # (void)
126             {
127 0     0     my $self = shift;
128 0           $self->idx_check();
129 0 0         (!$self->p_container()->size())
130             ? $self->arr_idx(-1)
131             : $self->arr_idx(0);
132 0           return $self; # iterator
133             }
134             sub last # (void)
135             {
136 0     0     my $self = shift;
137 0           $self->idx_check();
138 0 0         (!$self->p_container()->size())
139             ? $self->arr_idx(-1)
140             : $self->arr_idx($self->p_container()->size()-1);
141 0           return $self; # iterator
142             }
143             sub front_inserter # (container) -- static function
144             {
145 0     0     my $c = shift;
146 0 0 0       confess "A front_insert_iterator can only be used with a container that defines the push_front() member function\n"
      0        
147             unless (ref($c) && $c->isa('Class::STL::Containers::Abstract') && $c->can('push_front'));
148 0           return Class::STL::Iterators::FrontInsertIterator->new(p_container => $c);
149             }
150             sub back_inserter # (container) -- static function
151             {
152 0     0     my $c = shift;
153 0 0 0       confess "A back_insert_iterator can only be used with a container that defines the push_back() member function\n"
      0        
154             unless (ref($c) && $c->isa('Class::STL::Containers::Abstract') && $c->can('push_back'));
155 0           return Class::STL::Iterators::BackInsertIterator->new(p_container => $c);
156             }
157             sub inserter # (container, iterator) -- static function
158             {
159 0     0     my $c = shift;
160 0           my $i = shift;
161 0 0 0       confess "Usage:inserter(container, iterator)"
      0        
      0        
162             unless (ref($c) && $c->isa('Class::STL::Containers::Abstract')
163             && ref($i) && $i->isa('Class::STL::Iterators::Abstract'));
164 0           return Class::STL::Iterators::InsertIterator->new(p_container => $c, arr_idx => $i->arr_idx());
165             }
166             sub distance # (iterator, iterator) -- static function
167             {
168 0     0     my $iter_start = shift;
169 0           my $iter_finish = shift;
170 0 0 0       confess "@{[ __PACKAGE__ ]}::distance usage:\ndistance( iterator-start, iterator-finish );"
  0   0        
      0        
      0        
      0        
      0        
171             unless (
172             defined($iter_start) && ref($iter_start) && $iter_start->isa('Class::STL::Iterators::Abstract')
173             && defined($iter_finish) && ref($iter_finish) && $iter_finish->isa('Class::STL::Iterators::Abstract')
174             && $iter_start->p_container() == $iter_finish->p_container()
175             );
176 0 0 0       return -1 if ($iter_start->at_end() && $iter_finish->at_end());
177 0 0 0       return -1 if ($iter_start->at_end() || $iter_start->gt($iter_finish));
178 0 0         return $iter_finish->p_container()->size()-1 - $iter_start->arr_idx() if ($iter_finish->at_end());
179 0           return $iter_finish->arr_idx() - $iter_start->arr_idx();
180             }
181             sub advance # (size) -- static function
182             {
183 0     0     my $iter = shift;
184 0           my $size = shift;
185 0 0         if ($size >= 0)
186             {
187 0           for (my $i=0; $i<$size; ++$i) { $iter->next(); }
  0            
188             }
189             else
190             {
191 0           for (my $i=$size; $i!=0; ++$i) { $iter->prev(); }
  0            
192             }
193 0           return $iter;
194             }
195             sub retreat # (size) -- static function
196             {
197 0     0     my $iter = shift;
198 0           my $size = shift;
199 0           return $iter->advance(-$size);
200 0           return $iter;
201             }
202             sub eq # (element)
203             {
204 0     0     my $self = shift;
205 0           my $other = shift;
206             return
207             #? $self->p_container() == $other->p_container()
208 0           $self->arr_idx() == $other->arr_idx();
209             }
210             sub ne # (element)
211             {
212 0     0     my $self = shift;
213 0 0         return $self->eq(shift) ? 0 : 1;
214             }
215             sub gt # (element)
216             {
217 0     0     my $self = shift;
218 0           my $other = shift;
219 0   0       return !$self->at_end() && !$other->at_end()
220             #? && $self->p_container() == $other->p_container()
221             && $self->arr_idx() > $other->arr_idx();
222             }
223             sub ge # (element)
224             {
225 0     0     my $self = shift;
226 0           my $other = shift;
227 0   0       return !$self->at_end() && !$other->at_end()
228             #? && $self->p_container() == $other->p_container()
229             && $self->arr_idx() >= $other->arr_idx();
230             }
231             sub lt # (element)
232             {
233 0     0     my $self = shift;
234 0           my $other = shift;
235 0   0       return !$self->at_end() && !$other->at_end()
236             #? && $self->p_container() == $other->p_container()
237             && $self->arr_idx() < $other->arr_idx();
238             }
239             sub le # (element)
240             {
241 0     0     my $self = shift;
242 0           my $other = shift;
243 0   0       return !$self->at_end() && !$other->at_end()
244             #? && $self->p_container() == $other->p_container() # -- don't want overloaded == !!
245             && $self->arr_idx() <= $other->arr_idx();
246             }
247             sub cmp # (element)
248             {
249 0     0     my $self = shift;
250 0           my $other = shift;
251 0 0         return $self->eq($other) ? 0 : $self->lt($other) ? -1 : 1;
    0          
252             }
253             sub _bool
254             {
255 0     0     my $self = shift;
256 0           return $self;
257             }
258             }
259             # ----------------------------------------------------------------------------------------------------
260             {
261             package Class::STL::Iterators::BiDirectional;
262 7     7   58 use base qw(Class::STL::Iterators::Abstract);
  7         25  
  7         4304  
263 7     7   50 use Class::STL::ClassMembers;
  7         14  
  7         46  
264 7     7   38 use Class::STL::ClassMembers::Constructor;
  7         13  
  7         47  
265             }
266             # ----------------------------------------------------------------------------------------------------
267             {
268             package Class::STL::Iterators::Forward;
269 7     7   34 use base qw(Class::STL::Iterators::BiDirectional);
  7         13  
  7         4481  
270 7     7   48 use Class::STL::ClassMembers;
  7         11  
  7         42  
271 7     7   39 use Class::STL::ClassMembers::Constructor;
  7         16  
  7         39  
272 7     7   14800 use Class::STL::ClassMembers::Disable qw(prev);
  7         21  
  7         51  
273 7     7   40 use Class::STL::ClassMembers::Disable qw(last);
  7         13  
  7         31  
274             }
275             # ----------------------------------------------------------------------------------------------------
276             {
277             package Class::STL::Iterators::Reverse;
278 7     7   39 use base qw(Class::STL::Iterators::BiDirectional);
  7         14  
  7         5376  
279 7     7   53 use Class::STL::ClassMembers;
  7         34  
  7         58  
280 7     7   47 use Class::STL::ClassMembers::Constructor;
  7         15  
  7         73  
281             sub last # (void)
282             {
283 0     0     my $self = shift;
284 0           return $self->SUPER::first(); # iterator
285             }
286             sub first # (void)
287             {
288 0     0     my $self = shift;
289 0           return $self->SUPER::last(); # iterator
290             }
291             sub next # (void)
292             {
293 0     0     my $self = shift;
294 0           return $self->SUPER::prev(); # iterator
295             }
296             sub prev # (void)
297             {
298 0     0     my $self = shift;
299 0           return $self->SUPER::next(); # iterator
300             }
301             }
302             # ----------------------------------------------------------------------------------------------------
303             {
304             package Class::STL::Iterators::BackInsertIterator;
305 7     7   49 use base qw(Class::STL::Iterators::Abstract);
  7         69  
  7         4021  
306 7     7   47 use Class::STL::ClassMembers;
  7         16  
  7         52  
307 7     7   45 use Class::STL::ClassMembers::Constructor;
  7         12  
  7         42  
308             sub assign # (element)
309             {
310 0     0     my $self = shift;
311 0           $self->p_container()->push_back(@_);
312             }
313             }
314             # ----------------------------------------------------------------------------------------------------
315             {
316             package Class::STL::Iterators::FrontInsertIterator;
317 7     7   39 use base qw(Class::STL::Iterators::Abstract);
  7         12  
  7         3972  
318 7     7   43 use Class::STL::ClassMembers;
  7         13  
  7         225  
319 7     7   39 use Class::STL::ClassMembers::Constructor;
  7         13  
  7         38  
320             sub assign # (element)
321             {
322 0     0     my $self = shift;
323 0           $self->p_container()->push_front(@_);
324             }
325             }
326             # ----------------------------------------------------------------------------------------------------
327             {
328             package Class::STL::Iterators::InsertIterator;
329 7     7   54 use base qw(Class::STL::Iterators::Abstract);
  7         16  
  7         3754  
330 7     7   52 use Class::STL::ClassMembers;
  7         18  
  7         43  
331 7     7   41 use Class::STL::ClassMembers::Constructor;
  7         13  
  7         42  
332             sub assign # (element)
333             {
334 0     0     my $self = shift;
335 0 0 0       if (!$self->p_container()->size() || $self->at_end())
336             {
337 0           $self->p_container()->push(@_);
338             }
339             else
340             {
341 0   0       CORE::splice(@{$self->p_container()->data()}, $self->arr_idx(), 0,
  0            
342             grep(ref && $_->isa('Class::STL::Element'), @_));
343             }
344 0           return $self->next();
345             }
346             }
347             # ----------------------------------------------------------------------------------------------------
348             1;