[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 package Hash::Util; 2 3 require 5.007003; 4 use strict; 5 use Carp; 6 use warnings; 7 use warnings::register; 8 use Scalar::Util qw(reftype); 9 10 require Exporter; 11 our @ISA = qw(Exporter); 12 our @EXPORT_OK = qw( 13 fieldhash fieldhashes 14 15 all_keys 16 lock_keys unlock_keys 17 lock_value unlock_value 18 lock_hash unlock_hash 19 lock_keys_plus hash_locked 20 hidden_keys legal_keys 21 22 lock_ref_keys unlock_ref_keys 23 lock_ref_value unlock_ref_value 24 lock_hashref unlock_hashref 25 lock_ref_keys_plus hashref_locked 26 hidden_ref_keys legal_ref_keys 27 28 hash_seed hv_store 29 30 ); 31 our $VERSION = 0.07; 32 require DynaLoader; 33 local @ISA = qw(DynaLoader); 34 bootstrap Hash::Util $VERSION; 35 36 sub import { 37 my $class = shift; 38 if ( grep /fieldhash/, @_ ) { 39 require Hash::Util::FieldHash; 40 Hash::Util::FieldHash->import(':all'); # for re-export 41 } 42 unshift @_, $class; 43 goto &Exporter::import; 44 } 45 46 47 =head1 NAME 48 49 Hash::Util - A selection of general-utility hash subroutines 50 51 =head1 SYNOPSIS 52 53 # Restricted hashes 54 55 use Hash::Util qw( 56 hash_seed all_keys 57 lock_keys unlock_keys 58 lock_value unlock_value 59 lock_hash unlock_hash 60 lock_keys_plus hash_locked 61 hidden_keys legal_keys 62 ); 63 64 %hash = (foo => 42, bar => 23); 65 # Ways to restrict a hash 66 lock_keys(%hash); 67 lock_keys(%hash, @keyset); 68 lock_keys_plus(%hash, @additional_keys); 69 70 # Ways to inspect the properties of a restricted hash 71 my @legal = legal_keys(%hash); 72 my @hidden = hidden_keys(%hash); 73 my $ref = all_keys(%hash,@keys,@hidden); 74 my $is_locked = hash_locked(%hash); 75 76 # Remove restrictions on the hash 77 unlock_keys(%hash); 78 79 # Lock individual values in a hash 80 lock_value (%hash, 'foo'); 81 unlock_value(%hash, 'foo'); 82 83 # Ways to change the restrictions on both keys and values 84 lock_hash (%hash); 85 unlock_hash(%hash); 86 87 my $hashes_are_randomised = hash_seed() != 0; 88 89 =head1 DESCRIPTION 90 91 C<Hash::Util> and C<Hash::Util::FieldHash> contain special functions 92 for manipulating hashes that don't really warrant a keyword. 93 94 C<Hash::Util> contains a set of functions that support 95 L<restricted hashes|/"Restricted hashes">. These are described in 96 this document. C<Hash::Util::FieldHash> contains an (unrelated) 97 set of functions that support the use of hashes in 98 I<inside-out classes>, described in L<Hash::Util::FieldHash>. 99 100 By default C<Hash::Util> does not export anything. 101 102 =head2 Restricted hashes 103 104 5.8.0 introduces the ability to restrict a hash to a certain set of 105 keys. No keys outside of this set can be added. It also introduces 106 the ability to lock an individual key so it cannot be deleted and the 107 ability to ensure that an individual value cannot be changed. 108 109 This is intended to largely replace the deprecated pseudo-hashes. 110 111 =over 4 112 113 =item B<lock_keys> 114 115 =item B<unlock_keys> 116 117 lock_keys(%hash); 118 lock_keys(%hash, @keys); 119 120 Restricts the given %hash's set of keys to @keys. If @keys is not 121 given it restricts it to its current keyset. No more keys can be 122 added. delete() and exists() will still work, but will not alter 123 the set of allowed keys. B<Note>: the current implementation prevents 124 the hash from being bless()ed while it is in a locked state. Any attempt 125 to do so will raise an exception. Of course you can still bless() 126 the hash before you call lock_keys() so this shouldn't be a problem. 127 128 unlock_keys(%hash); 129 130 Removes the restriction on the %hash's keyset. 131 132 B<Note> that if any of the values of the hash have been locked they will not be unlocked 133 after this sub executes. 134 135 Both routines return a reference to the hash operated on. 136 137 =cut 138 139 sub lock_ref_keys { 140 my($hash, @keys) = @_; 141 142 Internals::hv_clear_placeholders %$hash; 143 if( @keys ) { 144 my %keys = map { ($_ => 1) } @keys; 145 my %original_keys = map { ($_ => 1) } keys %$hash; 146 foreach my $k (keys %original_keys) { 147 croak "Hash has key '$k' which is not in the new key set" 148 unless $keys{$k}; 149 } 150 151 foreach my $k (@keys) { 152 $hash->{$k} = undef unless exists $hash->{$k}; 153 } 154 Internals::SvREADONLY %$hash, 1; 155 156 foreach my $k (@keys) { 157 delete $hash->{$k} unless $original_keys{$k}; 158 } 159 } 160 else { 161 Internals::SvREADONLY %$hash, 1; 162 } 163 164 return $hash; 165 } 166 167 sub unlock_ref_keys { 168 my $hash = shift; 169 170 Internals::SvREADONLY %$hash, 0; 171 return $hash; 172 } 173 174 sub lock_keys (\%;@) { lock_ref_keys(@_) } 175 sub unlock_keys (\%) { unlock_ref_keys(@_) } 176 177 =item B<lock_keys_plus> 178 179 lock_keys_plus(%hash,@additional_keys) 180 181 Similar to C<lock_keys()>, with the difference being that the optional key list 182 specifies keys that may or may not be already in the hash. Essentially this is 183 an easier way to say 184 185 lock_keys(%hash,@additional_keys,keys %hash); 186 187 Returns a reference to %hash 188 189 =cut 190 191 192 sub lock_ref_keys_plus { 193 my ($hash,@keys)=@_; 194 my @delete; 195 Internals::hv_clear_placeholders(%$hash); 196 foreach my $key (@keys) { 197 unless (exists($hash->{$key})) { 198 $hash->{$key}=undef; 199 push @delete,$key; 200 } 201 } 202 Internals::SvREADONLY(%$hash,1); 203 delete @{$hash}{@delete}; 204 return $hash 205 } 206 207 sub lock_keys_plus(\%;@) { lock_ref_keys_plus(@_) } 208 209 210 =item B<lock_value> 211 212 =item B<unlock_value> 213 214 lock_value (%hash, $key); 215 unlock_value(%hash, $key); 216 217 Locks and unlocks the value for an individual key of a hash. The value of a 218 locked key cannot be changed. 219 220 Unless %hash has already been locked the key/value could be deleted 221 regardless of this setting. 222 223 Returns a reference to the %hash. 224 225 =cut 226 227 sub lock_ref_value { 228 my($hash, $key) = @_; 229 # I'm doubtful about this warning, as it seems not to be true. 230 # Marking a value in the hash as RO is useful, regardless 231 # of the status of the hash itself. 232 carp "Cannot usefully lock values in an unlocked hash" 233 if !Internals::SvREADONLY(%$hash) && warnings::enabled; 234 Internals::SvREADONLY $hash->{$key}, 1; 235 return $hash 236 } 237 238 sub unlock_ref_value { 239 my($hash, $key) = @_; 240 Internals::SvREADONLY $hash->{$key}, 0; 241 return $hash 242 } 243 244 sub lock_value (\%$) { lock_ref_value(@_) } 245 sub unlock_value (\%$) { unlock_ref_value(@_) } 246 247 248 =item B<lock_hash> 249 250 =item B<unlock_hash> 251 252 lock_hash(%hash); 253 254 lock_hash() locks an entire hash, making all keys and values read-only. 255 No value can be changed, no keys can be added or deleted. 256 257 unlock_hash(%hash); 258 259 unlock_hash() does the opposite of lock_hash(). All keys and values 260 are made writable. All values can be changed and keys can be added 261 and deleted. 262 263 Returns a reference to the %hash. 264 265 =cut 266 267 sub lock_hashref { 268 my $hash = shift; 269 270 lock_ref_keys($hash); 271 272 foreach my $value (values %$hash) { 273 Internals::SvREADONLY($value,1); 274 } 275 276 return $hash; 277 } 278 279 sub unlock_hashref { 280 my $hash = shift; 281 282 foreach my $value (values %$hash) { 283 Internals::SvREADONLY($value, 0); 284 } 285 286 unlock_ref_keys($hash); 287 288 return $hash; 289 } 290 291 sub lock_hash (\%) { lock_hashref(@_) } 292 sub unlock_hash (\%) { unlock_hashref(@_) } 293 294 =item B<lock_hash_recurse> 295 296 =item B<unlock_hash_recurse> 297 298 lock_hash_recurse(%hash); 299 300 lock_hash() locks an entire hash and any hashes it references recursively, 301 making all keys and values read-only. No value can be changed, no keys can 302 be added or deleted. 303 304 B<Only> recurses into hashes that are referenced by another hash. Thus a 305 Hash of Hashes (HoH) will all be restricted, but a Hash of Arrays of Hashes 306 (HoAoH) will only have the top hash restricted. 307 308 unlock_hash_recurse(%hash); 309 310 unlock_hash_recurse() does the opposite of lock_hash_recurse(). All keys and 311 values are made writable. All values can be changed and keys can be added 312 and deleted. Identical recursion restrictions apply as to lock_hash_recurse(). 313 314 Returns a reference to the %hash. 315 316 =cut 317 318 sub lock_hashref_recurse { 319 my $hash = shift; 320 321 lock_ref_keys($hash); 322 foreach my $value (values %$hash) { 323 if (reftype($value) eq 'HASH') { 324 lock_hashref_recurse($value); 325 } 326 Internals::SvREADONLY($value,1); 327 } 328 return $hash 329 } 330 331 sub unlock_hashref_recurse { 332 my $hash = shift; 333 334 foreach my $value (values %$hash) { 335 if (reftype($value) eq 'HASH') { 336 unlock_hashref_recurse($value); 337 } 338 Internals::SvREADONLY($value,1); 339 } 340 unlock_ref_keys($hash); 341 return $hash; 342 } 343 344 sub lock_hash_recurse (\%) { lock_hashref_recurse(@_) } 345 sub unlock_hash_recurse (\%) { unlock_hashref_recurse(@_) } 346 347 348 =item B<hash_unlocked> 349 350 hash_unlocked(%hash) and print "Hash is unlocked!\n"; 351 352 Returns true if the hash and its keys are unlocked. 353 354 =cut 355 356 sub hashref_unlocked { 357 my $hash=shift; 358 return Internals::SvREADONLY($hash) 359 } 360 361 sub hash_unlocked(\%) { hashref_unlocked(@_) } 362 363 =for demerphqs_editor 364 sub legal_ref_keys{} 365 sub hidden_ref_keys{} 366 sub all_keys{} 367 368 =cut 369 370 sub legal_keys(\%) { legal_ref_keys(@_) } 371 sub hidden_keys(\%){ hidden_ref_keys(@_) } 372 373 =item B<legal_keys> 374 375 my @keys = legal_keys(%hash); 376 377 Returns the list of the keys that are legal in a restricted hash. 378 In the case of an unrestricted hash this is identical to calling 379 keys(%hash). 380 381 =item B<hidden_keys> 382 383 my @keys = hidden_keys(%hash); 384 385 Returns the list of the keys that are legal in a restricted hash but 386 do not have a value associated to them. Thus if 'foo' is a 387 "hidden" key of the %hash it will return false for both C<defined> 388 and C<exists> tests. 389 390 In the case of an unrestricted hash this will return an empty list. 391 392 B<NOTE> this is an experimental feature that is heavily dependent 393 on the current implementation of restricted hashes. Should the 394 implementation change, this routine may become meaningless, in which 395 case it will return an empty list. 396 397 =item B<all_keys> 398 399 all_keys(%hash,@keys,@hidden); 400 401 Populates the arrays @keys with the all the keys that would pass 402 an C<exists> tests, and populates @hidden with the remaining legal 403 keys that have not been utilized. 404 405 Returns a reference to the hash. 406 407 In the case of an unrestricted hash this will be equivalent to 408 409 $ref = do { 410 @keys = keys %hash; 411 @hidden = (); 412 \%hash 413 }; 414 415 B<NOTE> this is an experimental feature that is heavily dependent 416 on the current implementation of restricted hashes. Should the 417 implementation change this routine may become meaningless in which 418 case it will behave identically to how it would behave on an 419 unrestricted hash. 420 421 =item B<hash_seed> 422 423 my $hash_seed = hash_seed(); 424 425 hash_seed() returns the seed number used to randomise hash ordering. 426 Zero means the "traditional" random hash ordering, non-zero means the 427 new even more random hash ordering introduced in Perl 5.8.1. 428 429 B<Note that the hash seed is sensitive information>: by knowing it one 430 can craft a denial-of-service attack against Perl code, even remotely, 431 see L<perlsec/"Algorithmic Complexity Attacks"> for more information. 432 B<Do not disclose the hash seed> to people who don't need to know it. 433 See also L<perlrun/PERL_HASH_SEED_DEBUG>. 434 435 =cut 436 437 sub hash_seed () { 438 Internals::rehash_seed(); 439 } 440 441 =item B<hv_store> 442 443 my $sv = 0; 444 hv_store(%hash,$key,$sv) or die "Failed to alias!"; 445 $hash{$key} = 1; 446 print $sv; # prints 1 447 448 Stores an alias to a variable in a hash instead of copying the value. 449 450 =back 451 452 =head2 Operating on references to hashes. 453 454 Most subroutines documented in this module have equivalent versions 455 that operate on references to hashes instead of native hashes. 456 The following is a list of these subs. They are identical except 457 in name and in that instead of taking a %hash they take a $hashref, 458 and additionally are not prototyped. 459 460 =over 4 461 462 =item lock_ref_keys 463 464 =item unlock_ref_keys 465 466 =item lock_ref_keys_plus 467 468 =item lock_ref_value 469 470 =item unlock_ref_value 471 472 =item lock_hashref 473 474 =item unlock_hashref 475 476 =item lock_hashref_recurse 477 478 =item unlock_hashref_recurse 479 480 =item hash_ref_unlocked 481 482 =item legal_ref_keys 483 484 =item hidden_ref_keys 485 486 =back 487 488 =head1 CAVEATS 489 490 Note that the trapping of the restricted operations is not atomic: 491 for example 492 493 eval { %hash = (illegal_key => 1) } 494 495 leaves the C<%hash> empty rather than with its original contents. 496 497 =head1 BUGS 498 499 The interface exposed by this module is very close to the current 500 implementation of restricted hashes. Over time it is expected that 501 this behavior will be extended and the interface abstracted further. 502 503 =head1 AUTHOR 504 505 Michael G Schwern <schwern@pobox.com> on top of code by Nick 506 Ing-Simmons and Jeffrey Friedl. 507 508 hv_store() is from Array::RefElem, Copyright 2000 Gisle Aas. 509 510 Additional code by Yves Orton. 511 512 =head1 SEE ALSO 513 514 L<Scalar::Util>, L<List::Util> and L<perlsec/"Algorithmic Complexity Attacks">. 515 516 L<Hash::Util::FieldHash>. 517 518 =cut 519 520 1;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |