| Filename | /usr/share/perl5/Readonly.pm |
| Statements | Executed 33 statements in 2.56ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 57µs | 57µs | Readonly::Array::BEGIN@107 |
| 1 | 1 | 1 | 34µs | 34µs | Koha::Calendar::BEGIN@20 |
| 1 | 1 | 1 | 16µs | 44µs | Readonly::BEGIN@177 |
| 1 | 1 | 1 | 12µs | 55µs | Readonly::BEGIN@42 |
| 1 | 1 | 1 | 11µs | 42µs | Readonly::BEGIN@39 |
| 1 | 1 | 1 | 11µs | 16µs | Koha::Calendar::BEGIN@21 |
| 1 | 1 | 1 | 9µs | 81µs | Readonly::BEGIN@178 |
| 0 | 0 | 0 | 0s | 0s | Readonly::Array |
| 0 | 0 | 0 | 0s | 0s | Readonly::Array1 |
| 0 | 0 | 0 | 0s | 0s | Readonly::Array::FETCH |
| 0 | 0 | 0 | 0s | 0s | Readonly::Array::FETCHSIZE |
| 0 | 0 | 0 | 0s | 0s | Readonly::Array::TIEARRAY |
| 0 | 0 | 0 | 0s | 0s | Readonly::Array::__ANON__[:119] |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash1 |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash::EXISTS |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash::FETCH |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash::FIRSTKEY |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash::NEXTKEY |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash::TIEHASH |
| 0 | 0 | 0 | 0s | 0s | Readonly::Hash::__ANON__[:169] |
| 0 | 0 | 0 | 0s | 0s | Readonly::Scalar |
| 0 | 0 | 0 | 0s | 0s | Readonly::Scalar1 |
| 0 | 0 | 0 | 0s | 0s | Readonly::Scalar::FETCH |
| 0 | 0 | 0 | 0s | 0s | Readonly::Scalar::TIESCALAR |
| 0 | 0 | 0 | 0s | 0s | Readonly::Scalar::__ANON__[:76] |
| 0 | 0 | 0 | 0s | 0s | Readonly::_is_badtype |
| 0 | 0 | 0 | 0s | 0s | Readonly::croak |
| 0 | 0 | 0 | 0s | 0s | Readonly::is_sv_readonly |
| 0 | 0 | 0 | 0s | 0s | Readonly::make_sv_readonly |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | =for gpg | ||||
| 2 | |||||
| - - | |||||
| 18 | # Rest of documentation is after __END__. | ||||
| 19 | |||||
| 20 | 3 | 47µs | 1 | 34µs | # spent 34µs within Koha::Calendar::BEGIN@20 which was called:
# once (34µs+0s) by Koha::Calendar::BEGIN@11 at line 20 # spent 34µs making 1 call to Koha::Calendar::BEGIN@20 |
| 21 | 3 | 194µs | 2 | 21µs | # spent 16µs (11+5) within Koha::Calendar::BEGIN@21 which was called:
# once (11µs+5µs) by Koha::Calendar::BEGIN@11 at line 21 # spent 16µs making 1 call to Koha::Calendar::BEGIN@21
# spent 5µs making 1 call to strict::import |
| 22 | #use warnings; | ||||
| 23 | #no warnings 'uninitialized'; | ||||
| 24 | |||||
| 25 | package Readonly; | ||||
| 26 | 1 | 800ns | $Readonly::VERSION = '1.03'; # Also change in the documentation! | ||
| 27 | |||||
| 28 | # Autocroak (Thanks, MJD) | ||||
| 29 | # Only load Carp.pm if module is croaking. | ||||
| 30 | sub croak | ||||
| 31 | { | ||||
| 32 | require Carp; | ||||
| 33 | goto &Carp::croak; | ||||
| 34 | } | ||||
| 35 | |||||
| 36 | # These functions may be overridden by Readonly::XS, if installed. | ||||
| 37 | sub is_sv_readonly ($) { 0 } | ||||
| 38 | sub make_sv_readonly ($) { die "make_sv_readonly called but not overridden" } | ||||
| 39 | 3 | 34µs | 2 | 73µs | # spent 42µs (11+31) within Readonly::BEGIN@39 which was called:
# once (11µs+31µs) by Koha::Calendar::BEGIN@11 at line 39 # spent 42µs making 1 call to Readonly::BEGIN@39
# spent 31µs making 1 call to vars::import |
| 40 | |||||
| 41 | # Common error messages, or portions thereof | ||||
| 42 | 3 | 438µs | 2 | 97µs | # spent 55µs (12+42) within Readonly::BEGIN@42 which was called:
# once (12µs+42µs) by Koha::Calendar::BEGIN@11 at line 42 # spent 55µs making 1 call to Readonly::BEGIN@42
# spent 42µs making 1 call to vars::import |
| 43 | 1 | 400ns | $MODIFY = 'Modification of a read-only value attempted'; | ||
| 44 | 1 | 300ns | $REASSIGN = 'Attempt to reassign a readonly'; | ||
| 45 | 1 | 300ns | $ODDHASH = 'May not store an odd number of values in a hash'; | ||
| 46 | |||||
| 47 | # See if we can use the XS stuff. | ||||
| 48 | 1 | 300ns | $Readonly::XS::MAGIC_COOKIE = "Do NOT use or require Readonly::XS unless you're me."; | ||
| 49 | 1 | 42µs | eval 'use Readonly::XS'; # spent 154µs executing statements in string eval # includes 441µs spent executing 1 call to 1 sub defined therein. | ||
| 50 | |||||
| 51 | |||||
| 52 | # ---------------- | ||||
| 53 | # Read-only scalars | ||||
| 54 | # ---------------- | ||||
| 55 | package Readonly::Scalar; | ||||
| 56 | |||||
| 57 | sub TIESCALAR | ||||
| 58 | { | ||||
| 59 | my $whence = (caller 2)[3]; # Check if naughty user is trying to tie directly. | ||||
| 60 | Readonly::croak "Invalid tie" unless $whence && $whence =~ /^Readonly::(?:Scalar1?|Readonly)$/; | ||||
| 61 | my $class = shift; | ||||
| 62 | Readonly::croak "No value specified for readonly scalar" unless @_; | ||||
| 63 | Readonly::croak "Too many values specified for readonly scalar" unless @_ == 1; | ||||
| 64 | |||||
| 65 | my $value = shift; | ||||
| 66 | return bless \$value, $class; | ||||
| 67 | } | ||||
| 68 | |||||
| 69 | sub FETCH | ||||
| 70 | { | ||||
| 71 | my $self = shift; | ||||
| 72 | return $$self; | ||||
| 73 | } | ||||
| 74 | |||||
| 75 | *STORE = *UNTIE = | ||||
| 76 | 1 | 5µs | sub {Readonly::croak $Readonly::MODIFY}; | ||
| 77 | |||||
| 78 | |||||
| 79 | # ---------------- | ||||
| 80 | # Read-only arrays | ||||
| 81 | # ---------------- | ||||
| 82 | package Readonly::Array; | ||||
| 83 | |||||
| 84 | sub TIEARRAY | ||||
| 85 | { | ||||
| 86 | my $whence = (caller 1)[3]; # Check if naughty user is trying to tie directly. | ||||
| 87 | Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Array1?$/; | ||||
| 88 | my $class = shift; | ||||
| 89 | my @self = @_; | ||||
| 90 | |||||
| 91 | return bless \@self, $class; | ||||
| 92 | } | ||||
| 93 | |||||
| 94 | sub FETCH | ||||
| 95 | { | ||||
| 96 | my $self = shift; | ||||
| 97 | my $index = shift; | ||||
| 98 | return $self->[$index]; | ||||
| 99 | } | ||||
| 100 | |||||
| 101 | sub FETCHSIZE | ||||
| 102 | { | ||||
| 103 | my $self = shift; | ||||
| 104 | return scalar @$self; | ||||
| 105 | } | ||||
| 106 | |||||
| 107 | # spent 57µs within Readonly::Array::BEGIN@107 which was called:
# once (57µs+0s) by Koha::Calendar::BEGIN@11 at line 116 | ||||
| 108 | 1 | 59µs | eval q{ | ||
| 109 | sub EXISTS | ||||
| 110 | { | ||||
| 111 | my $self = shift; | ||||
| 112 | my $index = shift; | ||||
| 113 | return exists $self->[$index]; | ||||
| 114 | } | ||||
| 115 | } if $] >= 5.006; # couldn't do "exists" on arrays before then | ||||
| 116 | 1 | 321µs | 1 | 57µs | } # spent 57µs making 1 call to Readonly::Array::BEGIN@107 |
| 117 | |||||
| 118 | *STORE = *STORESIZE = *EXTEND = *PUSH = *POP = *UNSHIFT = *SHIFT = *SPLICE = *CLEAR = *UNTIE = | ||||
| 119 | 1 | 4µs | sub {Readonly::croak $Readonly::MODIFY}; | ||
| 120 | |||||
| 121 | |||||
| 122 | # ---------------- | ||||
| 123 | # Read-only hashes | ||||
| 124 | # ---------------- | ||||
| 125 | package Readonly::Hash; | ||||
| 126 | |||||
| 127 | sub TIEHASH | ||||
| 128 | { | ||||
| 129 | my $whence = (caller 1)[3]; # Check if naughty user is trying to tie directly. | ||||
| 130 | Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Hash1?$/; | ||||
| 131 | |||||
| 132 | my $class = shift; | ||||
| 133 | # must have an even number of values | ||||
| 134 | Readonly::croak $Readonly::ODDHASH unless (@_ %2 == 0); | ||||
| 135 | |||||
| 136 | my %self = @_; | ||||
| 137 | return bless \%self, $class; | ||||
| 138 | } | ||||
| 139 | |||||
| 140 | sub FETCH | ||||
| 141 | { | ||||
| 142 | my $self = shift; | ||||
| 143 | my $key = shift; | ||||
| 144 | |||||
| 145 | return $self->{$key}; | ||||
| 146 | } | ||||
| 147 | |||||
| 148 | sub EXISTS | ||||
| 149 | { | ||||
| 150 | my $self = shift; | ||||
| 151 | my $key = shift; | ||||
| 152 | return exists $self->{$key}; | ||||
| 153 | } | ||||
| 154 | |||||
| 155 | sub FIRSTKEY | ||||
| 156 | { | ||||
| 157 | my $self = shift; | ||||
| 158 | my $dummy = keys %$self; | ||||
| 159 | return scalar each %$self; | ||||
| 160 | } | ||||
| 161 | |||||
| 162 | sub NEXTKEY | ||||
| 163 | { | ||||
| 164 | my $self = shift; | ||||
| 165 | return scalar each %$self; | ||||
| 166 | } | ||||
| 167 | |||||
| 168 | *STORE = *DELETE = *CLEAR = *UNTIE = | ||||
| 169 | 1 | 2µs | sub {Readonly::croak $Readonly::MODIFY}; | ||
| 170 | |||||
| 171 | |||||
| 172 | # ---------------------------------------------------------------- | ||||
| 173 | # Main package, containing convenience functions (so callers won't | ||||
| 174 | # have to explicitly tie the variables themselves). | ||||
| 175 | # ---------------------------------------------------------------- | ||||
| 176 | package Readonly; | ||||
| 177 | 3 | 47µs | 2 | 73µs | # spent 44µs (16+28) within Readonly::BEGIN@177 which was called:
# once (16µs+28µs) by Koha::Calendar::BEGIN@11 at line 177 # spent 44µs making 1 call to Readonly::BEGIN@177
# spent 28µs making 1 call to Exporter::import |
| 178 | 3 | 1.10ms | 2 | 152µs | # spent 81µs (9+71) within Readonly::BEGIN@178 which was called:
# once (9µs+71µs) by Koha::Calendar::BEGIN@11 at line 178 # spent 81µs making 1 call to Readonly::BEGIN@178
# spent 71µs making 1 call to vars::import |
| 179 | 1 | 11µs | push @ISA, 'Exporter'; | ||
| 180 | 1 | 600ns | push @EXPORT, qw/Readonly/; | ||
| 181 | 1 | 1µs | push @EXPORT_OK, qw/Scalar Array Hash Scalar1 Array1 Hash1/; | ||
| 182 | |||||
| 183 | # Predeclare the following, so we can use them recursively | ||||
| 184 | sub Scalar ($$); | ||||
| 185 | sub Array (\@;@); | ||||
| 186 | sub Hash (\%;@); | ||||
| 187 | |||||
| 188 | # Returns true if a string begins with "Readonly::" | ||||
| 189 | # Used to prevent reassignment of Readonly variables. | ||||
| 190 | sub _is_badtype | ||||
| 191 | { | ||||
| 192 | my $type = $_[0]; | ||||
| 193 | return lc $type if $type =~ s/^Readonly:://; | ||||
| 194 | return; | ||||
| 195 | } | ||||
| 196 | |||||
| 197 | # Shallow Readonly scalar | ||||
| 198 | sub Scalar1 ($$) | ||||
| 199 | { | ||||
| 200 | croak "$REASSIGN scalar" if is_sv_readonly $_[0]; | ||||
| 201 | my $badtype = _is_badtype (ref tied $_[0]); | ||||
| 202 | croak "$REASSIGN $badtype" if $badtype; | ||||
| 203 | |||||
| 204 | # xs method: flag scalar as readonly | ||||
| 205 | if ($XSokay) | ||||
| 206 | { | ||||
| 207 | $_[0] = $_[1]; | ||||
| 208 | make_sv_readonly $_[0]; | ||||
| 209 | return; | ||||
| 210 | } | ||||
| 211 | |||||
| 212 | # pure-perl method: tied scalar | ||||
| 213 | my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $_[1]}; | ||||
| 214 | if ($@) | ||||
| 215 | { | ||||
| 216 | croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY; | ||||
| 217 | die $@; # some other error? | ||||
| 218 | } | ||||
| 219 | return $tieobj; | ||||
| 220 | } | ||||
| 221 | |||||
| 222 | # Shallow Readonly array | ||||
| 223 | sub Array1 (\@;@) | ||||
| 224 | { | ||||
| 225 | my $badtype = _is_badtype (ref tied $_[0]); | ||||
| 226 | croak "$REASSIGN $badtype" if $badtype; | ||||
| 227 | |||||
| 228 | my $aref = shift; | ||||
| 229 | return tie @$aref, 'Readonly::Array', @_; | ||||
| 230 | } | ||||
| 231 | |||||
| 232 | # Shallow Readonly hash | ||||
| 233 | sub Hash1 (\%;@) | ||||
| 234 | { | ||||
| 235 | my $badtype = _is_badtype (ref tied $_[0]); | ||||
| 236 | croak "$REASSIGN $badtype" if $badtype; | ||||
| 237 | |||||
| 238 | my $href = shift; | ||||
| 239 | |||||
| 240 | # If only one value, and it's a hashref, expand it | ||||
| 241 | if (@_ == 1 && ref $_[0] eq 'HASH') | ||||
| 242 | { | ||||
| 243 | return tie %$href, 'Readonly::Hash', %{$_[0]}; | ||||
| 244 | } | ||||
| 245 | |||||
| 246 | # otherwise, must have an even number of values | ||||
| 247 | croak $ODDHASH unless (@_%2 == 0); | ||||
| 248 | |||||
| 249 | return tie %$href, 'Readonly::Hash', @_; | ||||
| 250 | } | ||||
| 251 | |||||
| 252 | # Deep Readonly scalar | ||||
| 253 | sub Scalar ($$) | ||||
| 254 | { | ||||
| 255 | croak "$REASSIGN scalar" if is_sv_readonly $_[0]; | ||||
| 256 | my $badtype = _is_badtype (ref tied $_[0]); | ||||
| 257 | croak "$REASSIGN $badtype" if $badtype; | ||||
| 258 | |||||
| 259 | my $value = $_[1]; | ||||
| 260 | |||||
| 261 | # Recursively check passed element for references; if any, make them Readonly | ||||
| 262 | foreach ($value) | ||||
| 263 | { | ||||
| 264 | if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v} | ||||
| 265 | elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v} | ||||
| 266 | elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v} | ||||
| 267 | } | ||||
| 268 | |||||
| 269 | # xs method: flag scalar as readonly | ||||
| 270 | if ($XSokay) | ||||
| 271 | { | ||||
| 272 | $_[0] = $value; | ||||
| 273 | make_sv_readonly $_[0]; | ||||
| 274 | return; | ||||
| 275 | } | ||||
| 276 | |||||
| 277 | # pure-perl method: tied scalar | ||||
| 278 | my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $value}; | ||||
| 279 | if ($@) | ||||
| 280 | { | ||||
| 281 | croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY; | ||||
| 282 | die $@; # some other error? | ||||
| 283 | } | ||||
| 284 | return $tieobj; | ||||
| 285 | } | ||||
| 286 | |||||
| 287 | # Deep Readonly array | ||||
| 288 | sub Array (\@;@) | ||||
| 289 | { | ||||
| 290 | my $badtype = _is_badtype (ref tied @{$_[0]}); | ||||
| 291 | croak "$REASSIGN $badtype" if $badtype; | ||||
| 292 | |||||
| 293 | my $aref = shift; | ||||
| 294 | my @values = @_; | ||||
| 295 | |||||
| 296 | # Recursively check passed elements for references; if any, make them Readonly | ||||
| 297 | foreach (@values) | ||||
| 298 | { | ||||
| 299 | if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v} | ||||
| 300 | elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v} | ||||
| 301 | elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v} | ||||
| 302 | } | ||||
| 303 | # Lastly, tie the passed reference | ||||
| 304 | return tie @$aref, 'Readonly::Array', @values; | ||||
| 305 | } | ||||
| 306 | |||||
| 307 | # Deep Readonly hash | ||||
| 308 | sub Hash (\%;@) | ||||
| 309 | { | ||||
| 310 | my $badtype = _is_badtype (ref tied %{$_[0]}); | ||||
| 311 | croak "$REASSIGN $badtype" if $badtype; | ||||
| 312 | |||||
| 313 | my $href = shift; | ||||
| 314 | my @values = @_; | ||||
| 315 | |||||
| 316 | # If only one value, and it's a hashref, expand it | ||||
| 317 | if (@_ == 1 && ref $_[0] eq 'HASH') | ||||
| 318 | { | ||||
| 319 | @values = %{$_[0]}; | ||||
| 320 | } | ||||
| 321 | |||||
| 322 | # otherwise, must have an even number of values | ||||
| 323 | croak $ODDHASH unless (@values %2 == 0); | ||||
| 324 | |||||
| 325 | # Recursively check passed elements for references; if any, make them Readonly | ||||
| 326 | foreach (@values) | ||||
| 327 | { | ||||
| 328 | if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v} | ||||
| 329 | elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v} | ||||
| 330 | elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v} | ||||
| 331 | } | ||||
| 332 | |||||
| 333 | return tie %$href, 'Readonly::Hash', @values; | ||||
| 334 | } | ||||
| 335 | |||||
| 336 | |||||
| 337 | # Common entry-point for all supported data types | ||||
| 338 | 1 | 239µs | eval q{sub Readonly} . ( $] < 5.008 ? '' : '(\[$@%]@)' ) . <<'SUB_READONLY'; | ||
| 339 | { | ||||
| 340 | if (ref $_[0] eq 'SCALAR') | ||||
| 341 | { | ||||
| 342 | croak $MODIFY if is_sv_readonly ${$_[0]}; | ||||
| 343 | my $badtype = _is_badtype (ref tied ${$_[0]}); | ||||
| 344 | croak "$REASSIGN $badtype" if $badtype; | ||||
| 345 | croak "Readonly scalar must have only one value" if @_ > 2; | ||||
| 346 | |||||
| 347 | my $tieobj = eval {tie ${$_[0]}, 'Readonly::Scalar', $_[1]}; | ||||
| 348 | # Tie may have failed because user tried to tie a constant, or we screwed up somehow. | ||||
| 349 | if ($@) | ||||
| 350 | { | ||||
| 351 | croak $MODIFY if $@ =~ /^$MODIFY at/; # Point the finger at the user. | ||||
| 352 | die "$@\n"; # Not a modify read-only message; must be our fault. | ||||
| 353 | } | ||||
| 354 | return $tieobj; | ||||
| 355 | } | ||||
| 356 | elsif (ref $_[0] eq 'ARRAY') | ||||
| 357 | { | ||||
| 358 | my $aref = shift; | ||||
| 359 | return Array @$aref, @_; | ||||
| 360 | } | ||||
| 361 | elsif (ref $_[0] eq 'HASH') | ||||
| 362 | { | ||||
| 363 | my $href = shift; | ||||
| 364 | croak $ODDHASH if @_%2 != 0 && !(@_ == 1 && ref $_[0] eq 'HASH'); | ||||
| 365 | return Hash %$href, @_; | ||||
| 366 | } | ||||
| 367 | elsif (ref $_[0]) | ||||
| 368 | { | ||||
| 369 | croak "Readonly only supports scalar, array, and hash variables."; | ||||
| 370 | } | ||||
| 371 | else | ||||
| 372 | { | ||||
| 373 | croak "First argument to Readonly must be a reference."; | ||||
| 374 | } | ||||
| 375 | } | ||||
| 376 | SUB_READONLY | ||||
| 377 | |||||
| 378 | |||||
| 379 | 1 | 14µs | 1; | ||
| 380 | __END__ |