| Filename | /home/ss5/perl5/perlbrew/perls/perl-5.14.1/lib/site_perl/5.14.1/Iterator.pm |
| Statements | Executed 13 statements in 4.12ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 5.82ms | 43.0ms | Iterator::BEGIN@22 |
| 1 | 1 | 1 | 54µs | 69µs | Iterator::Util::BEGIN@15 |
| 1 | 1 | 1 | 29µs | 58µs | Iterator::Util::BEGIN@16 |
| 1 | 1 | 1 | 17µs | 17µs | Iterator::BEGIN@69 |
| 0 | 0 | 0 | 0s | 0s | Iterator::DESTROY |
| 0 | 0 | 0 | 0s | 0s | Iterator::X::Internal_Error::location |
| 0 | 0 | 0 | 0s | 0s | Iterator::X::full_message |
| 0 | 0 | 0 | 0s | 0s | Iterator::X::location |
| 0 | 0 | 0 | 0s | 0s | Iterator::__ANON__[:78] |
| 0 | 0 | 0 | 0s | 0s | Iterator::_initialize |
| 0 | 0 | 0 | 0s | 0s | Iterator::is_done |
| 0 | 0 | 0 | 0s | 0s | Iterator::is_exhausted |
| 0 | 0 | 0 | 0s | 0s | Iterator::isnt_exhausted |
| 0 | 0 | 0 | 0s | 0s | Iterator::new |
| 0 | 0 | 0 | 0s | 0s | Iterator::value |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | =for gpg | ||||
| 2 | -----BEGIN PGP SIGNED MESSAGE----- | ||||
| 3 | Hash: SHA1 | ||||
| 4 | |||||
| 5 | =head1 NAME | ||||
| 6 | |||||
| 7 | Iterator - A general-purpose iterator class. | ||||
| 8 | |||||
| 9 | =head1 VERSION | ||||
| 10 | |||||
| 11 | This documentation describes version 0.03 of Iterator.pm, October 10, 2005. | ||||
| 12 | |||||
| 13 | =cut | ||||
| 14 | |||||
| 15 | 2 | 94µs | 2 | 84µs | # spent 69µs (54+15) within Iterator::Util::BEGIN@15 which was called:
# once (54µs+15µs) by Iterator::Util::BEGIN@28 at line 15 # spent 69µs making 1 call to Iterator::Util::BEGIN@15
# spent 15µs making 1 call to strict::import |
| 16 | 2 | 505µs | 2 | 88µs | # spent 58µs (29+29) within Iterator::Util::BEGIN@16 which was called:
# once (29µs+29µs) by Iterator::Util::BEGIN@28 at line 16 # spent 58µs making 1 call to Iterator::Util::BEGIN@16
# spent 29µs making 1 call to warnings::import |
| 17 | package Iterator; | ||||
| 18 | 1 | 3µs | our $VERSION = '0.03'; | ||
| 19 | |||||
| 20 | # Declare exception classes | ||||
| 21 | use Exception::Class | ||||
| 22 | # spent 43.0ms (5.82+37.1) within Iterator::BEGIN@22 which was called:
# once (5.82ms+37.1ms) by Iterator::Util::BEGIN@28 at line 65 | ||||
| 23 | 1 | 62µs | 1 | 7.40ms | 'Iterator::X' => # spent 7.40ms making 1 call to Exception::Class::import |
| 24 | { | ||||
| 25 | description => 'Generic Iterator exception', | ||||
| 26 | }, | ||||
| 27 | 'Iterator::X::Parameter_Error' => | ||||
| 28 | { | ||||
| 29 | isa => 'Iterator::X', | ||||
| 30 | description => 'Iterator method parameter error', | ||||
| 31 | }, | ||||
| 32 | 'Iterator::X::OptionError' => | ||||
| 33 | { | ||||
| 34 | isa => 'Iterator::X', | ||||
| 35 | fields => 'name', | ||||
| 36 | description => 'A bad option was passed to an iterator method or function', | ||||
| 37 | }, | ||||
| 38 | 'Iterator::X::Exhausted' => | ||||
| 39 | { | ||||
| 40 | isa => 'Iterator::X', | ||||
| 41 | description => 'Attempt to next_value () on an exhausted iterator', | ||||
| 42 | }, | ||||
| 43 | 'Iterator::X::Am_Now_Exhausted' => | ||||
| 44 | { | ||||
| 45 | isa => 'Iterator::X', | ||||
| 46 | description => 'Signals Iterator object that it is now exhausted', | ||||
| 47 | }, | ||||
| 48 | 'Iterator::X::User_Code_Error' => | ||||
| 49 | { | ||||
| 50 | isa => 'Iterator::X', | ||||
| 51 | fields => 'eval_error', | ||||
| 52 | description => q{An exception was thrown within the user's code}, | ||||
| 53 | }, | ||||
| 54 | 'Iterator::X::IO_Error' => | ||||
| 55 | { | ||||
| 56 | isa => 'Iterator::X', | ||||
| 57 | fields => 'os_error', | ||||
| 58 | description => q{An I/O error occurred}, | ||||
| 59 | }, | ||||
| 60 | 'Iterator::X::Internal_Error' => | ||||
| 61 | { | ||||
| 62 | isa => 'Iterator::X', | ||||
| 63 | description => 'An Iterator.pm internal error. Please contact author.', | ||||
| 64 | }, | ||||
| 65 | 1 | 653µs | 1 | 43.0ms | ); # spent 43.0ms making 1 call to Iterator::BEGIN@22 |
| 66 | |||||
| 67 | # Class method to help caller catch exceptions | ||||
| 68 | BEGIN | ||||
| 69 | # spent 17µs within Iterator::BEGIN@69 which was called:
# once (17µs+0s) by Iterator::Util::BEGIN@28 at line 80 | ||||
| 70 | # Dave Rolsky added this subroutine in v1.22 of Exception::Class. | ||||
| 71 | # Thanks, Dave! | ||||
| 72 | # We define it here so we have the functionality in pre-1.22 versions; | ||||
| 73 | # we make it conditional so as to avoid a warning in post-1.22 versions. | ||||
| 74 | *Exception::Class::Base::caught = sub | ||||
| 75 | { | ||||
| 76 | my $class = shift; | ||||
| 77 | return Exception::Class->caught($class); | ||||
| 78 | } | ||||
| 79 | 1 | 18µs | if $Exception::Class::VERSION lt '1.22'; | ||
| 80 | 1 | 2.76ms | 1 | 17µs | } # spent 17µs making 1 call to Iterator::BEGIN@69 |
| 81 | |||||
| 82 | # Croak-like location of error | ||||
| 83 | sub Iterator::X::location | ||||
| 84 | { | ||||
| 85 | my ($pkg,$file,$line); | ||||
| 86 | my $caller_level = 0; | ||||
| 87 | while (1) | ||||
| 88 | { | ||||
| 89 | ($pkg,$file,$line) = caller($caller_level++); | ||||
| 90 | last if $pkg !~ /\A Iterator/x && $pkg !~ /\A Exception::Class/x | ||||
| 91 | } | ||||
| 92 | return "at $file line $line"; | ||||
| 93 | } | ||||
| 94 | |||||
| 95 | # Die-like location of error | ||||
| 96 | sub Iterator::X::Internal_Error::location | ||||
| 97 | { | ||||
| 98 | my $self = shift; | ||||
| 99 | return "at " . $self->file () . " line " . $self->line () | ||||
| 100 | } | ||||
| 101 | |||||
| 102 | # Override full_message, to report location of error in caller's code. | ||||
| 103 | sub Iterator::X::full_message | ||||
| 104 | { | ||||
| 105 | my $self = shift; | ||||
| 106 | |||||
| 107 | my $msg = $self->message; | ||||
| 108 | return $msg if substr($msg,-1,1) eq "\n"; | ||||
| 109 | |||||
| 110 | $msg =~ s/[ \t]+\z//; # remove any trailing spaces (is this necessary?) | ||||
| 111 | return $msg . q{ } . $self->location () . qq{\n}; | ||||
| 112 | } | ||||
| 113 | |||||
| 114 | |||||
| 115 | ## Constructor | ||||
| 116 | |||||
| 117 | # Method name: new | ||||
| 118 | # Synopsis: $iterator = Iterator->new( $code_ref ); | ||||
| 119 | # Description: Object constructor. | ||||
| 120 | # Created: 07/27/2005 by EJR | ||||
| 121 | # Parameters: $code_ref - the iterator sequence generation code. | ||||
| 122 | # Returns: New Iterator. | ||||
| 123 | # Exceptions: Iterator::X::Parameter_Error (via _initialize) | ||||
| 124 | sub new | ||||
| 125 | { | ||||
| 126 | my $class = shift; | ||||
| 127 | my $self = \do {my $anonymous}; | ||||
| 128 | bless $self, $class; | ||||
| 129 | $self->_initialize(@_); | ||||
| 130 | return $self; | ||||
| 131 | } | ||||
| 132 | |||||
| 133 | { # encapsulation enclosure | ||||
| 134 | |||||
| 135 | # Attributes: | ||||
| 136 | 2 | 3µs | my %code_for; # The sequence code (coderef) for each object. | ||
| 137 | 1 | 400ns | my %is_exhausted; # Boolean: is this object exhausted? | ||
| 138 | 1 | 3µs | my %next_value_for; # One-item lookahead buffer for each object. | ||
| 139 | # [if you update this list of attributes, be sure to edit DESTROY] | ||||
| 140 | |||||
| 141 | # Method name: _initialize | ||||
| 142 | # Synopsis: $iterator->_initialize( $code_ref ); | ||||
| 143 | # Description: Object initializer. | ||||
| 144 | # Created: 07/27/2005 by EJR | ||||
| 145 | # Parameters: $code_ref - the iterator sequence generation code. | ||||
| 146 | # Returns: Nothing. | ||||
| 147 | # Exceptions: Iterator::X::Parameter_Error | ||||
| 148 | # Iterator::X::User_Code_Error | ||||
| 149 | # Notes: For internal module use only. | ||||
| 150 | # Caches the first value of the iterator in %next_value_for. | ||||
| 151 | sub _initialize | ||||
| 152 | { | ||||
| 153 | my $self = shift; | ||||
| 154 | |||||
| 155 | Iterator::X::Parameter_Error->throw(q{Too few parameters to Iterator->new()}) | ||||
| 156 | if @_ < 1; | ||||
| 157 | Iterator::X::Parameter_Error->throw(q{Too many parameters to Iterator->new()}) | ||||
| 158 | if @_ > 1; | ||||
| 159 | my $code = shift; | ||||
| 160 | Iterator::X::Parameter_Error->throw (q{Parameter to Iterator->new() must be code reference}) | ||||
| 161 | if ref $code ne 'CODE'; | ||||
| 162 | |||||
| 163 | $code_for {$self} = $code; | ||||
| 164 | |||||
| 165 | # Get the next (first) value for this iterator | ||||
| 166 | eval | ||||
| 167 | { | ||||
| 168 | $next_value_for{$self} = $code-> (); | ||||
| 169 | }; | ||||
| 170 | |||||
| 171 | my $ex; | ||||
| 172 | if ($ex = Iterator::X::Am_Now_Exhausted->caught ()) | ||||
| 173 | { | ||||
| 174 | # Starting off exhausted is okay | ||||
| 175 | $is_exhausted{$self} = 1; | ||||
| 176 | } | ||||
| 177 | elsif ($@) | ||||
| 178 | { | ||||
| 179 | Iterator::X::User_Code_Error->throw (message => "$@", | ||||
| 180 | eval_error => $@); | ||||
| 181 | } | ||||
| 182 | |||||
| 183 | return; | ||||
| 184 | } | ||||
| 185 | |||||
| 186 | # Method name: DESTROY | ||||
| 187 | # Synopsis: (none) | ||||
| 188 | # Description: Object destructor. | ||||
| 189 | # Created: 07/27/2005 by EJR | ||||
| 190 | # Parameters: None. | ||||
| 191 | # Returns: Nothing. | ||||
| 192 | # Exceptions: None. | ||||
| 193 | # Notes: Invoked automatically by perl. | ||||
| 194 | # Releases the hash entries used by the object. | ||||
| 195 | # Module would leak memory otherwise. | ||||
| 196 | sub DESTROY | ||||
| 197 | { | ||||
| 198 | my $self = shift; | ||||
| 199 | delete $code_for{$self}; | ||||
| 200 | delete $is_exhausted{$self}; | ||||
| 201 | delete $next_value_for{$self}; | ||||
| 202 | } | ||||
| 203 | |||||
| 204 | # Method name: value | ||||
| 205 | # Synopsis: $next_value = $iterator->value(); | ||||
| 206 | # Description: Returns each value of the sequence in turn. | ||||
| 207 | # Created: 07/27/2005 by EJR | ||||
| 208 | # Parameters: None. | ||||
| 209 | # Returns: Next value, as generated by caller's code ref. | ||||
| 210 | # Exceptions: Iterator::X::Exhausted | ||||
| 211 | # Notes: Keeps one forward-looking value for the iterator in | ||||
| 212 | # %next_value_for. This is so we have something to | ||||
| 213 | # return when user's code throws Am_Now_Exhausted. | ||||
| 214 | sub value | ||||
| 215 | { | ||||
| 216 | my $self = shift; | ||||
| 217 | |||||
| 218 | Iterator::X::Exhausted->throw(q{Iterator is exhausted}) | ||||
| 219 | if $is_exhausted{$self}; | ||||
| 220 | |||||
| 221 | # The value that we'll be returning this time. | ||||
| 222 | my $this_value = $next_value_for{$self}; | ||||
| 223 | |||||
| 224 | # Compute the value that we'll return next time | ||||
| 225 | eval | ||||
| 226 | { | ||||
| 227 | $next_value_for{$self} = $code_for{$self}->(@_); | ||||
| 228 | }; | ||||
| 229 | if (my $ex = Iterator::X::Am_Now_Exhausted->caught ()) | ||||
| 230 | { | ||||
| 231 | # Aha, we're done; we'll have to stop next time. | ||||
| 232 | $is_exhausted{$self} = 1; | ||||
| 233 | } | ||||
| 234 | elsif ($@) | ||||
| 235 | { | ||||
| 236 | Iterator::X::User_Code_Error->throw (message => "$@", | ||||
| 237 | eval_error => $@); | ||||
| 238 | } | ||||
| 239 | |||||
| 240 | return $this_value; | ||||
| 241 | } | ||||
| 242 | |||||
| 243 | # Method name: is_exhausted | ||||
| 244 | # Synopsis: $boolean = $iterator->is_exhausted(); | ||||
| 245 | # Description: Flag indicating that the iterator is exhausted. | ||||
| 246 | # Created: 07/27/2005 by EJR | ||||
| 247 | # Parameters: None. | ||||
| 248 | # Returns: Current value of %is_exhausted for this object. | ||||
| 249 | # Exceptions: None. | ||||
| 250 | sub is_exhausted | ||||
| 251 | { | ||||
| 252 | my $self = shift; | ||||
| 253 | |||||
| 254 | return $is_exhausted{$self}; | ||||
| 255 | } | ||||
| 256 | |||||
| 257 | # Method name: isnt_exhausted | ||||
| 258 | # Synopsis: $boolean = $iterator->isnt_exhausted(); | ||||
| 259 | # Description: Flag indicating that the iterator is NOT exhausted. | ||||
| 260 | # Created: 07/27/2005 by EJR | ||||
| 261 | # Parameters: None. | ||||
| 262 | # Returns: Logical NOT of %is_exhausted for this object. | ||||
| 263 | # Exceptions: None. | ||||
| 264 | sub isnt_exhausted | ||||
| 265 | { | ||||
| 266 | my $self = shift; | ||||
| 267 | |||||
| 268 | return ! $is_exhausted{$self}; | ||||
| 269 | } | ||||
| 270 | |||||
| 271 | } # end of encapsulation enclosure | ||||
| 272 | |||||
| 273 | |||||
| 274 | # Function name: is_done | ||||
| 275 | # Synopsis: Iterator::is_done (); | ||||
| 276 | # Description: Convenience function. Throws an Am_Now_Exhausted exception. | ||||
| 277 | # Created: 08/02/2005 by EJR, per Will Coleda's suggestion. | ||||
| 278 | # Parameters: None. | ||||
| 279 | # Returns: Doesn't return. | ||||
| 280 | # Exceptions: Iterator::X::Am_Now_Exhausted | ||||
| 281 | sub is_done | ||||
| 282 | { | ||||
| 283 | Iterator::X::Am_Now_Exhausted->throw() | ||||
| 284 | } | ||||
| 285 | |||||
| 286 | |||||
| 287 | 1 | 18µs | 1; | ||
| 288 | __END__ |