1package Hash::Util; 2 3require 5.007003; 4use strict; 5use Carp; 6use warnings; 7no warnings 'uninitialized'; 8use warnings::register; 9use Scalar::Util qw(reftype); 10 11require Exporter; 12our @ISA = qw(Exporter); 13our @EXPORT_OK = qw( 14 fieldhash fieldhashes 15 16 all_keys 17 lock_keys unlock_keys 18 lock_value unlock_value 19 lock_hash unlock_hash 20 lock_keys_plus hash_locked 21 hidden_keys legal_keys 22 23 lock_ref_keys unlock_ref_keys 24 lock_ref_value unlock_ref_value 25 lock_hashref unlock_hashref 26 lock_ref_keys_plus hashref_locked 27 hidden_ref_keys legal_ref_keys 28 29 hash_seed hv_store 30 31 ); 32our $VERSION = '0.11'; 33require XSLoader; 34XSLoader::load(); 35 36sub 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 49Hash::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 91C<Hash::Util> and C<Hash::Util::FieldHash> contain special functions 92for manipulating hashes that don't really warrant a keyword. 93 94C<Hash::Util> contains a set of functions that support 95L<restricted hashes|/"Restricted hashes">. These are described in 96this document. C<Hash::Util::FieldHash> contains an (unrelated) 97set of functions that support the use of hashes in 98I<inside-out classes>, described in L<Hash::Util::FieldHash>. 99 100By default C<Hash::Util> does not export anything. 101 102=head2 Restricted hashes 103 1045.8.0 introduces the ability to restrict a hash to a certain set of 105keys. No keys outside of this set can be added. It also introduces 106the ability to lock an individual key so it cannot be deleted and the 107ability to ensure that an individual value cannot be changed. 108 109This 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 120Restricts the given %hash's set of keys to @keys. If @keys is not 121given it restricts it to its current keyset. No more keys can be 122added. delete() and exists() will still work, but will not alter 123the set of allowed keys. B<Note>: the current implementation prevents 124the hash from being bless()ed while it is in a locked state. Any attempt 125to do so will raise an exception. Of course you can still bless() 126the hash before you call lock_keys() so this shouldn't be a problem. 127 128 unlock_keys(%hash); 129 130Removes the restriction on the %hash's keyset. 131 132B<Note> that if any of the values of the hash have been locked they will not be unlocked 133after this sub executes. 134 135Both routines return a reference to the hash operated on. 136 137=cut 138 139sub 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 167sub unlock_ref_keys { 168 my $hash = shift; 169 170 Internals::SvREADONLY %$hash, 0; 171 return $hash; 172} 173 174sub lock_keys (\%;@) { lock_ref_keys(@_) } 175sub unlock_keys (\%) { unlock_ref_keys(@_) } 176 177=item B<lock_keys_plus> 178 179 lock_keys_plus(%hash,@additional_keys) 180 181Similar to C<lock_keys()>, with the difference being that the optional key list 182specifies keys that may or may not be already in the hash. Essentially this is 183an easier way to say 184 185 lock_keys(%hash,@additional_keys,keys %hash); 186 187Returns a reference to %hash 188 189=cut 190 191 192sub 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 207sub 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 217Locks and unlocks the value for an individual key of a hash. The value of a 218locked key cannot be changed. 219 220Unless %hash has already been locked the key/value could be deleted 221regardless of this setting. 222 223Returns a reference to the %hash. 224 225=cut 226 227sub 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 238sub unlock_ref_value { 239 my($hash, $key) = @_; 240 Internals::SvREADONLY $hash->{$key}, 0; 241 return $hash 242} 243 244sub lock_value (\%$) { lock_ref_value(@_) } 245sub unlock_value (\%$) { unlock_ref_value(@_) } 246 247 248=item B<lock_hash> 249 250=item B<unlock_hash> 251 252 lock_hash(%hash); 253 254lock_hash() locks an entire hash, making all keys and values read-only. 255No value can be changed, no keys can be added or deleted. 256 257 unlock_hash(%hash); 258 259unlock_hash() does the opposite of lock_hash(). All keys and values 260are made writable. All values can be changed and keys can be added 261and deleted. 262 263Returns a reference to the %hash. 264 265=cut 266 267sub 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 279sub 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 291sub lock_hash (\%) { lock_hashref(@_) } 292sub 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 300lock_hash() locks an entire hash and any hashes it references recursively, 301making all keys and values read-only. No value can be changed, no keys can 302be added or deleted. 303 304B<Only> recurses into hashes that are referenced by another hash. Thus a 305Hash 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 310unlock_hash_recurse() does the opposite of lock_hash_recurse(). All keys and 311values are made writable. All values can be changed and keys can be added 312and deleted. Identical recursion restrictions apply as to lock_hash_recurse(). 313 314Returns a reference to the %hash. 315 316=cut 317 318sub lock_hashref_recurse { 319 my $hash = shift; 320 321 lock_ref_keys($hash); 322 foreach my $value (values %$hash) { 323 my $type = reftype($value); 324 if (defined($type) and $type eq 'HASH') { 325 lock_hashref_recurse($value); 326 } 327 Internals::SvREADONLY($value,1); 328 } 329 return $hash 330} 331 332sub unlock_hashref_recurse { 333 my $hash = shift; 334 335 foreach my $value (values %$hash) { 336 my $type = reftype($value); 337 if (defined($type) and $type eq 'HASH') { 338 unlock_hashref_recurse($value); 339 } 340 Internals::SvREADONLY($value,1); 341 } 342 unlock_ref_keys($hash); 343 return $hash; 344} 345 346sub lock_hash_recurse (\%) { lock_hashref_recurse(@_) } 347sub unlock_hash_recurse (\%) { unlock_hashref_recurse(@_) } 348 349 350=item B<hash_unlocked> 351 352 hash_unlocked(%hash) and print "Hash is unlocked!\n"; 353 354Returns true if the hash and its keys are unlocked. 355 356=cut 357 358sub hashref_unlocked { 359 my $hash=shift; 360 return Internals::SvREADONLY($hash) 361} 362 363sub hash_unlocked(\%) { hashref_unlocked(@_) } 364 365=for demerphqs_editor 366sub legal_ref_keys{} 367sub hidden_ref_keys{} 368sub all_keys{} 369 370=cut 371 372sub legal_keys(\%) { legal_ref_keys(@_) } 373sub hidden_keys(\%){ hidden_ref_keys(@_) } 374 375=item B<legal_keys> 376 377 my @keys = legal_keys(%hash); 378 379Returns the list of the keys that are legal in a restricted hash. 380In the case of an unrestricted hash this is identical to calling 381keys(%hash). 382 383=item B<hidden_keys> 384 385 my @keys = hidden_keys(%hash); 386 387Returns the list of the keys that are legal in a restricted hash but 388do not have a value associated to them. Thus if 'foo' is a 389"hidden" key of the %hash it will return false for both C<defined> 390and C<exists> tests. 391 392In the case of an unrestricted hash this will return an empty list. 393 394B<NOTE> this is an experimental feature that is heavily dependent 395on the current implementation of restricted hashes. Should the 396implementation change, this routine may become meaningless, in which 397case it will return an empty list. 398 399=item B<all_keys> 400 401 all_keys(%hash,@keys,@hidden); 402 403Populates the arrays @keys with the all the keys that would pass 404an C<exists> tests, and populates @hidden with the remaining legal 405keys that have not been utilized. 406 407Returns a reference to the hash. 408 409In the case of an unrestricted hash this will be equivalent to 410 411 $ref = do { 412 @keys = keys %hash; 413 @hidden = (); 414 \%hash 415 }; 416 417B<NOTE> this is an experimental feature that is heavily dependent 418on the current implementation of restricted hashes. Should the 419implementation change this routine may become meaningless in which 420case it will behave identically to how it would behave on an 421unrestricted hash. 422 423=item B<hash_seed> 424 425 my $hash_seed = hash_seed(); 426 427hash_seed() returns the seed number used to randomise hash ordering. 428Zero means the "traditional" random hash ordering, non-zero means the 429new even more random hash ordering introduced in Perl 5.8.1. 430 431B<Note that the hash seed is sensitive information>: by knowing it one 432can craft a denial-of-service attack against Perl code, even remotely, 433see L<perlsec/"Algorithmic Complexity Attacks"> for more information. 434B<Do not disclose the hash seed> to people who don't need to know it. 435See also L<perlrun/PERL_HASH_SEED_DEBUG>. 436 437=cut 438 439sub hash_seed () { 440 Internals::rehash_seed(); 441} 442 443=item B<hv_store> 444 445 my $sv = 0; 446 hv_store(%hash,$key,$sv) or die "Failed to alias!"; 447 $hash{$key} = 1; 448 print $sv; # prints 1 449 450Stores an alias to a variable in a hash instead of copying the value. 451 452=back 453 454=head2 Operating on references to hashes. 455 456Most subroutines documented in this module have equivalent versions 457that operate on references to hashes instead of native hashes. 458The following is a list of these subs. They are identical except 459in name and in that instead of taking a %hash they take a $hashref, 460and additionally are not prototyped. 461 462=over 4 463 464=item lock_ref_keys 465 466=item unlock_ref_keys 467 468=item lock_ref_keys_plus 469 470=item lock_ref_value 471 472=item unlock_ref_value 473 474=item lock_hashref 475 476=item unlock_hashref 477 478=item lock_hashref_recurse 479 480=item unlock_hashref_recurse 481 482=item hash_ref_unlocked 483 484=item legal_ref_keys 485 486=item hidden_ref_keys 487 488=back 489 490=head1 CAVEATS 491 492Note that the trapping of the restricted operations is not atomic: 493for example 494 495 eval { %hash = (illegal_key => 1) } 496 497leaves the C<%hash> empty rather than with its original contents. 498 499=head1 BUGS 500 501The interface exposed by this module is very close to the current 502implementation of restricted hashes. Over time it is expected that 503this behavior will be extended and the interface abstracted further. 504 505=head1 AUTHOR 506 507Michael G Schwern <schwern@pobox.com> on top of code by Nick 508Ing-Simmons and Jeffrey Friedl. 509 510hv_store() is from Array::RefElem, Copyright 2000 Gisle Aas. 511 512Additional code by Yves Orton. 513 514=head1 SEE ALSO 515 516L<Scalar::Util>, L<List::Util> and L<perlsec/"Algorithmic Complexity Attacks">. 517 518L<Hash::Util::FieldHash>. 519 520=cut 521 5221; 523