xref: /openbsd-src/gnu/usr.bin/perl/ext/Hash-Util/lib/Hash/Util.pm (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
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
21                     hash_locked hash_unlocked
22                     hashref_locked hashref_unlocked
23                     hidden_keys legal_keys
24
25                     lock_ref_keys unlock_ref_keys
26                     lock_ref_value unlock_ref_value
27                     lock_hashref unlock_hashref
28                     lock_ref_keys_plus
29                     hidden_ref_keys legal_ref_keys
30
31                     hash_seed hash_value hv_store
32                     bucket_stats bucket_stats_formatted bucket_info bucket_array
33                     lock_hash_recurse unlock_hash_recurse
34                     lock_hashref_recurse unlock_hashref_recurse
35
36                     hash_traversal_mask
37                    );
38our $VERSION = '0.19';
39require XSLoader;
40XSLoader::load();
41
42sub import {
43    my $class = shift;
44    if ( grep /fieldhash/, @_ ) {
45        require Hash::Util::FieldHash;
46        Hash::Util::FieldHash->import(':all'); # for re-export
47    }
48    unshift @_, $class;
49    goto &Exporter::import;
50}
51
52
53=head1 NAME
54
55Hash::Util - A selection of general-utility hash subroutines
56
57=head1 SYNOPSIS
58
59  # Restricted hashes
60
61  use Hash::Util qw(
62                     fieldhash fieldhashes
63
64                     all_keys
65                     lock_keys unlock_keys
66                     lock_value unlock_value
67                     lock_hash unlock_hash
68                     lock_keys_plus
69                     hash_locked hash_unlocked
70                     hashref_locked hashref_unlocked
71                     hidden_keys legal_keys
72
73                     lock_ref_keys unlock_ref_keys
74                     lock_ref_value unlock_ref_value
75                     lock_hashref unlock_hashref
76                     lock_ref_keys_plus
77                     hidden_ref_keys legal_ref_keys
78
79                     hash_seed hash_value hv_store
80                     bucket_stats bucket_info bucket_array
81                     lock_hash_recurse unlock_hash_recurse
82                     lock_hashref_recurse unlock_hashref_recurse
83
84                     hash_traversal_mask
85                   );
86
87  %hash = (foo => 42, bar => 23);
88  # Ways to restrict a hash
89  lock_keys(%hash);
90  lock_keys(%hash, @keyset);
91  lock_keys_plus(%hash, @additional_keys);
92
93  # Ways to inspect the properties of a restricted hash
94  my @legal = legal_keys(%hash);
95  my @hidden = hidden_keys(%hash);
96  my $ref = all_keys(%hash,@keys,@hidden);
97  my $is_locked = hash_locked(%hash);
98
99  # Remove restrictions on the hash
100  unlock_keys(%hash);
101
102  # Lock individual values in a hash
103  lock_value  (%hash, 'foo');
104  unlock_value(%hash, 'foo');
105
106  # Ways to change the restrictions on both keys and values
107  lock_hash  (%hash);
108  unlock_hash(%hash);
109
110  my $hashes_are_randomised = hash_seed() != 0;
111
112  my $int_hash_value = hash_value( 'string' );
113
114  my $mask= hash_traversal_mask(%hash);
115
116  hash_traversal_mask(%hash,1234);
117
118=head1 DESCRIPTION
119
120C<Hash::Util> and C<Hash::Util::FieldHash> contain special functions
121for manipulating hashes that don't really warrant a keyword.
122
123C<Hash::Util> contains a set of functions that support
124L<restricted hashes|/"Restricted hashes">. These are described in
125this document.  C<Hash::Util::FieldHash> contains an (unrelated)
126set of functions that support the use of hashes in
127I<inside-out classes>, described in L<Hash::Util::FieldHash>.
128
129By default C<Hash::Util> does not export anything.
130
131=head2 Restricted hashes
132
1335.8.0 introduces the ability to restrict a hash to a certain set of
134keys.  No keys outside of this set can be added.  It also introduces
135the ability to lock an individual key so it cannot be deleted and the
136ability to ensure that an individual value cannot be changed.
137
138This is intended to largely replace the deprecated pseudo-hashes.
139
140=over 4
141
142=item B<lock_keys>
143
144=item B<unlock_keys>
145
146  lock_keys(%hash);
147  lock_keys(%hash, @keys);
148
149Restricts the given %hash's set of keys to @keys.  If @keys is not
150given it restricts it to its current keyset.  No more keys can be
151added. delete() and exists() will still work, but will not alter
152the set of allowed keys. B<Note>: the current implementation prevents
153the hash from being bless()ed while it is in a locked state. Any attempt
154to do so will raise an exception. Of course you can still bless()
155the hash before you call lock_keys() so this shouldn't be a problem.
156
157  unlock_keys(%hash);
158
159Removes the restriction on the %hash's keyset.
160
161B<Note> that if any of the values of the hash have been locked they will not
162be unlocked after this sub executes.
163
164Both routines return a reference to the hash operated on.
165
166=cut
167
168sub lock_ref_keys {
169    my($hash, @keys) = @_;
170
171    Internals::hv_clear_placeholders %$hash;
172    if( @keys ) {
173        my %keys = map { ($_ => 1) } @keys;
174        my %original_keys = map { ($_ => 1) } keys %$hash;
175        foreach my $k (keys %original_keys) {
176            croak "Hash has key '$k' which is not in the new key set"
177              unless $keys{$k};
178        }
179
180        foreach my $k (@keys) {
181            $hash->{$k} = undef unless exists $hash->{$k};
182        }
183        Internals::SvREADONLY %$hash, 1;
184
185        foreach my $k (@keys) {
186            delete $hash->{$k} unless $original_keys{$k};
187        }
188    }
189    else {
190        Internals::SvREADONLY %$hash, 1;
191    }
192
193    return $hash;
194}
195
196sub unlock_ref_keys {
197    my $hash = shift;
198
199    Internals::SvREADONLY %$hash, 0;
200    return $hash;
201}
202
203sub   lock_keys (\%;@) {   lock_ref_keys(@_) }
204sub unlock_keys (\%)   { unlock_ref_keys(@_) }
205
206=item B<lock_keys_plus>
207
208  lock_keys_plus(%hash,@additional_keys)
209
210Similar to C<lock_keys()>, with the difference being that the optional key list
211specifies keys that may or may not be already in the hash. Essentially this is
212an easier way to say
213
214  lock_keys(%hash,@additional_keys,keys %hash);
215
216Returns a reference to %hash
217
218=cut
219
220
221sub lock_ref_keys_plus {
222    my ($hash,@keys) = @_;
223    my @delete;
224    Internals::hv_clear_placeholders(%$hash);
225    foreach my $key (@keys) {
226        unless (exists($hash->{$key})) {
227            $hash->{$key}=undef;
228            push @delete,$key;
229        }
230    }
231    Internals::SvREADONLY(%$hash,1);
232    delete @{$hash}{@delete};
233    return $hash
234}
235
236sub lock_keys_plus(\%;@) { lock_ref_keys_plus(@_) }
237
238
239=item B<lock_value>
240
241=item B<unlock_value>
242
243  lock_value  (%hash, $key);
244  unlock_value(%hash, $key);
245
246Locks and unlocks the value for an individual key of a hash.  The value of a
247locked key cannot be changed.
248
249Unless %hash has already been locked the key/value could be deleted
250regardless of this setting.
251
252Returns a reference to the %hash.
253
254=cut
255
256sub lock_ref_value {
257    my($hash, $key) = @_;
258    # I'm doubtful about this warning, as it seems not to be true.
259    # Marking a value in the hash as RO is useful, regardless
260    # of the status of the hash itself.
261    carp "Cannot usefully lock values in an unlocked hash"
262      if !Internals::SvREADONLY(%$hash) && warnings::enabled;
263    Internals::SvREADONLY $hash->{$key}, 1;
264    return $hash
265}
266
267sub unlock_ref_value {
268    my($hash, $key) = @_;
269    Internals::SvREADONLY $hash->{$key}, 0;
270    return $hash
271}
272
273sub   lock_value (\%$) {   lock_ref_value(@_) }
274sub unlock_value (\%$) { unlock_ref_value(@_) }
275
276
277=item B<lock_hash>
278
279=item B<unlock_hash>
280
281    lock_hash(%hash);
282
283lock_hash() locks an entire hash, making all keys and values read-only.
284No value can be changed, no keys can be added or deleted.
285
286    unlock_hash(%hash);
287
288unlock_hash() does the opposite of lock_hash().  All keys and values
289are made writable.  All values can be changed and keys can be added
290and deleted.
291
292Returns a reference to the %hash.
293
294=cut
295
296sub lock_hashref {
297    my $hash = shift;
298
299    lock_ref_keys($hash);
300
301    foreach my $value (values %$hash) {
302        Internals::SvREADONLY($value,1);
303    }
304
305    return $hash;
306}
307
308sub unlock_hashref {
309    my $hash = shift;
310
311    foreach my $value (values %$hash) {
312        Internals::SvREADONLY($value, 0);
313    }
314
315    unlock_ref_keys($hash);
316
317    return $hash;
318}
319
320sub   lock_hash (\%) {   lock_hashref(@_) }
321sub unlock_hash (\%) { unlock_hashref(@_) }
322
323=item B<lock_hash_recurse>
324
325=item B<unlock_hash_recurse>
326
327    lock_hash_recurse(%hash);
328
329lock_hash() locks an entire hash and any hashes it references recursively,
330making all keys and values read-only. No value can be changed, no keys can
331be added or deleted.
332
333This method B<only> recurses into hashes that are referenced by another hash.
334Thus a Hash of Hashes (HoH) will all be restricted, but a Hash of Arrays of
335Hashes (HoAoH) will only have the top hash restricted.
336
337    unlock_hash_recurse(%hash);
338
339unlock_hash_recurse() does the opposite of lock_hash_recurse().  All keys and
340values are made writable.  All values can be changed and keys can be added
341and deleted. Identical recursion restrictions apply as to lock_hash_recurse().
342
343Returns a reference to the %hash.
344
345=cut
346
347sub lock_hashref_recurse {
348    my $hash = shift;
349
350    lock_ref_keys($hash);
351    foreach my $value (values %$hash) {
352        my $type = reftype($value);
353        if (defined($type) and $type eq 'HASH') {
354            lock_hashref_recurse($value);
355        }
356        Internals::SvREADONLY($value,1);
357    }
358    return $hash
359}
360
361sub unlock_hashref_recurse {
362    my $hash = shift;
363
364    foreach my $value (values %$hash) {
365        my $type = reftype($value);
366        if (defined($type) and $type eq 'HASH') {
367            unlock_hashref_recurse($value);
368        }
369        Internals::SvREADONLY($value,0);
370    }
371    unlock_ref_keys($hash);
372    return $hash;
373}
374
375sub   lock_hash_recurse (\%) {   lock_hashref_recurse(@_) }
376sub unlock_hash_recurse (\%) { unlock_hashref_recurse(@_) }
377
378=item B<hashref_locked>
379
380=item B<hash_locked>
381
382  hashref_locked(\%hash) and print "Hash is locked!\n";
383  hash_locked(%hash) and print "Hash is locked!\n";
384
385Returns true if the hash and its keys are locked.
386
387=cut
388
389sub hashref_locked {
390    my $hash=shift;
391    Internals::SvREADONLY(%$hash);
392}
393
394sub hash_locked(\%) { hashref_locked(@_) }
395
396=item B<hashref_unlocked>
397
398=item B<hash_unlocked>
399
400  hashref_unlocked(\%hash) and print "Hash is unlocked!\n";
401  hash_unlocked(%hash) and print "Hash is unlocked!\n";
402
403Returns true if the hash and its keys are unlocked.
404
405=cut
406
407sub hashref_unlocked {
408    my $hash=shift;
409    !Internals::SvREADONLY(%$hash);
410}
411
412sub hash_unlocked(\%) { hashref_unlocked(@_) }
413
414=for demerphqs_editor
415sub legal_ref_keys{}
416sub hidden_ref_keys{}
417sub all_keys{}
418
419=cut
420
421sub legal_keys(\%) { legal_ref_keys(@_)  }
422sub hidden_keys(\%){ hidden_ref_keys(@_) }
423
424=item B<legal_keys>
425
426  my @keys = legal_keys(%hash);
427
428Returns the list of the keys that are legal in a restricted hash.
429In the case of an unrestricted hash this is identical to calling
430keys(%hash).
431
432=item B<hidden_keys>
433
434  my @keys = hidden_keys(%hash);
435
436Returns the list of the keys that are legal in a restricted hash but
437do not have a value associated to them. Thus if 'foo' is a
438"hidden" key of the %hash it will return false for both C<defined>
439and C<exists> tests.
440
441In the case of an unrestricted hash this will return an empty list.
442
443B<NOTE> this is an experimental feature that is heavily dependent
444on the current implementation of restricted hashes. Should the
445implementation change, this routine may become meaningless, in which
446case it will return an empty list.
447
448=item B<all_keys>
449
450  all_keys(%hash,@keys,@hidden);
451
452Populates the arrays @keys with the all the keys that would pass
453an C<exists> tests, and populates @hidden with the remaining legal
454keys that have not been utilized.
455
456Returns a reference to the hash.
457
458In the case of an unrestricted hash this will be equivalent to
459
460  $ref = do {
461      @keys = keys %hash;
462      @hidden = ();
463      \%hash
464  };
465
466B<NOTE> this is an experimental feature that is heavily dependent
467on the current implementation of restricted hashes. Should the
468implementation change this routine may become meaningless in which
469case it will behave identically to how it would behave on an
470unrestricted hash.
471
472=item B<hash_seed>
473
474    my $hash_seed = hash_seed();
475
476hash_seed() returns the seed bytes used to randomise hash ordering.
477
478B<Note that the hash seed is sensitive information>: by knowing it one
479can craft a denial-of-service attack against Perl code, even remotely,
480see L<perlsec/"Algorithmic Complexity Attacks"> for more information.
481B<Do not disclose the hash seed> to people who don't need to know it.
482See also L<perlrun/PERL_HASH_SEED_DEBUG>.
483
484Prior to Perl 5.17.6 this function returned a UV, it now returns a string,
485which may be of nearly any size as determined by the hash function your
486Perl has been built with. Possible sizes may be but are not limited to
4874 bytes (for most hash algorithms) and 16 bytes (for siphash).
488
489=item B<hash_value>
490
491    my $hash_value = hash_value($string);
492
493hash_value() returns the current perl's internal hash value for a given
494string.
495
496Returns a 32 bit integer representing the hash value of the string passed
497in. This value is only reliable for the lifetime of the process. It may
498be different depending on invocation, environment variables,  perl version,
499architectures, and build options.
500
501B<Note that the hash value of a given string is sensitive information>:
502by knowing it one can deduce the hash seed which in turn can allow one to
503craft a denial-of-service attack against Perl code, even remotely,
504see L<perlsec/"Algorithmic Complexity Attacks"> for more information.
505B<Do not disclose the hash value of a string> to people who don't need to
506know it. See also L<perlrun/PERL_HASH_SEED_DEBUG>.
507
508=item B<bucket_info>
509
510Return a set of basic information about a hash.
511
512    my ($keys, $buckets, $used, @length_counts)= bucket_info($hash);
513
514Fields are as follows:
515
516    0: Number of keys in the hash
517    1: Number of buckets in the hash
518    2: Number of used buckets in the hash
519    rest : list of counts, Kth element is the number of buckets
520           with K keys in it.
521
522See also bucket_stats() and bucket_array().
523
524=item B<bucket_stats>
525
526Returns a list of statistics about a hash.
527
528 my ($keys, $buckets, $used, $quality, $utilization_ratio,
529        $collision_pct, $mean, $stddev, @length_counts)
530    = bucket_stats($hashref);
531
532Fields are as follows:
533
534    0: Number of keys in the hash
535    1: Number of buckets in the hash
536    2: Number of used buckets in the hash
537    3: Hash Quality Score
538    4: Percent of buckets used
539    5: Percent of keys which are in collision
540    6: Mean bucket length of occupied buckets
541    7: Standard Deviation of bucket lengths of occupied buckets
542    rest : list of counts, Kth element is the number of buckets
543           with K keys in it.
544
545See also bucket_info() and bucket_array().
546
547Note that Hash Quality Score would be 1 for an ideal hash, numbers
548close to and below 1 indicate good hashing, and number significantly
549above indicate a poor score. In practice it should be around 0.95 to 1.05.
550It is defined as:
551
552 $score= sum( $count[$length] * ($length * ($length + 1) / 2) )
553            /
554            ( ( $keys / 2 * $buckets ) *
555              ( $keys + ( 2 * $buckets ) - 1 ) )
556
557The formula is from the Red Dragon book (reformulated to use the data available)
558and is documented at L<http://www.strchr.com/hash_functions>
559
560=item B<bucket_array>
561
562    my $array= bucket_array(\%hash);
563
564Returns a packed representation of the bucket array associated with a hash. Each element
565of the array is either an integer K, in which case it represents K empty buckets, or
566a reference to another array which contains the keys that are in that bucket.
567
568B<Note that the information returned by bucket_array is sensitive information>:
569by knowing it one can directly attack perl's hash function which in turn may allow
570one to craft a denial-of-service attack against Perl code, even remotely,
571see L<perlsec/"Algorithmic Complexity Attacks"> for more information.
572B<Do not disclose the output of this function> to people who don't need to
573know it. See also L<perlrun/PERL_HASH_SEED_DEBUG>. This function is provided strictly
574for  debugging and diagnostics purposes only, it is hard to imagine a reason why it
575would be used in production code.
576
577=cut
578
579
580sub bucket_stats {
581    my ($hash) = @_;
582    my ($keys, $buckets, $used, @length_counts) = bucket_info($hash);
583    my $sum;
584    my $score;
585    for (1 .. $#length_counts) {
586        $sum += ($length_counts[$_] * $_);
587        $score += $length_counts[$_] * ( $_ * ($_ + 1 ) / 2 );
588    }
589    $score = $score /
590             (( $keys / (2 * $buckets )) * ( $keys + ( 2 * $buckets ) - 1 ))
591                 if $keys;
592    my ($mean, $stddev)= (0, 0);
593    if ($used) {
594        $mean= $sum / $used;
595        $sum= 0;
596        $sum += ($length_counts[$_] * (($_-$mean)**2)) for 1 .. $#length_counts;
597
598        $stddev= sqrt($sum/$used);
599    }
600    return $keys, $buckets, $used, $keys ? ($score, $used/$buckets, ($keys-$used)/$keys, $mean, $stddev, @length_counts) : ();
601}
602
603=item B<bucket_stats_formatted>
604
605  print bucket_stats_formatted($hashref);
606
607Return a formatted report of the information returned by bucket_stats().
608An example report looks like this:
609
610 Keys: 50 Buckets: 33/64 Quality-Score: 1.01 (Good)
611 Utilized Buckets: 51.56% Optimal: 78.12% Keys In Collision: 34.00%
612 Chain Length - mean: 1.52 stddev: 0.66
613 Buckets 64          [0000000000000000000000000000000111111111111111111122222222222333]
614 Len   0 Pct:  48.44 [###############################]
615 Len   1 Pct:  29.69 [###################]
616 Len   2 Pct:  17.19 [###########]
617 Len   3 Pct:   4.69 [###]
618 Keys    50          [11111111111111111111111111111111122222222222222333]
619 Pos   1 Pct:  66.00 [#################################]
620 Pos   2 Pct:  28.00 [##############]
621 Pos   3 Pct:   6.00 [###]
622
623The first set of stats gives some summary statistical information,
624including the quality score translated into "Good", "Poor" and "Bad",
625(score<=1.05, score<=1.2, score>1.2). See the documentation in
626bucket_stats() for more details.
627
628The two sets of barcharts give stats and a visual indication of performance
629of the hash.
630
631The first gives data on bucket chain lengths and provides insight on how
632much work a fetch *miss* will take. In this case we have to inspect every item
633in a bucket before we can be sure the item is not in the list. The performance
634for an insert is equivalent to this case, as is a delete where the item
635is not in the hash.
636
637The second gives data on how many keys are at each depth in the chain, and
638gives an idea of how much work a fetch *hit* will take. The performance for
639an update or delete of an item in the hash is equivalent to this case.
640
641Note that these statistics are summary only. Actual performance will depend
642on real hit/miss ratios accessing the hash. If you are concerned by hit ratios
643you are recommended to "oversize" your hash by using something like:
644
645   keys(%hash)= keys(%hash) << $k;
646
647With $k chosen carefully, and likely to be a small number like 1 or 2. In
648theory the larger the bucket array the less chance of collision.
649
650=cut
651
652
653sub _bucket_stats_formatted_bars {
654    my ($total, $ary, $start_idx, $title, $row_title)= @_;
655
656    my $return = "";
657    my $max_width= $total > 64 ? 64 : $total;
658    my $bar_width= $max_width / $total;
659
660    my $str= "";
661    if ( @$ary < 10) {
662        for my $idx ($start_idx .. $#$ary) {
663            $str .= $idx x sprintf("%.0f", ($ary->[$idx] * $bar_width));
664        }
665    } else {
666        $str= "-" x $max_width;
667    }
668    $return .= sprintf "%-7s         %6d [%s]\n",$title, $total, $str;
669
670    foreach my $idx ($start_idx .. $#$ary) {
671        $return .= sprintf "%-.3s %3d %6.2f%% %6d [%s]\n",
672            $row_title,
673            $idx,
674            $ary->[$idx] / $total * 100,
675            $ary->[$idx],
676            "#" x sprintf("%.0f", ($ary->[$idx] * $bar_width)),
677        ;
678    }
679    return $return;
680}
681
682sub bucket_stats_formatted {
683    my ($hashref)= @_;
684    my ($keys, $buckets, $used, $score, $utilization_ratio, $collision_pct,
685        $mean, $stddev, @length_counts) = bucket_stats($hashref);
686
687    my $return= sprintf   "Keys: %d Buckets: %d/%d Quality-Score: %.2f (%s)\n"
688                        . "Utilized Buckets: %.2f%% Optimal: %.2f%% Keys In Collision: %.2f%%\n"
689                        . "Chain Length - mean: %.2f stddev: %.2f\n",
690                $keys, $used, $buckets, $score, $score <= 1.05 ? "Good" : $score < 1.2 ? "Poor" : "Bad",
691                $utilization_ratio * 100,
692                $keys/$buckets * 100,
693                $collision_pct * 100,
694                $mean, $stddev;
695
696    my @key_depth;
697    $key_depth[$_]= $length_counts[$_] + ( $key_depth[$_+1] || 0 )
698        for reverse 1 .. $#length_counts;
699
700    if ($keys) {
701        $return .= _bucket_stats_formatted_bars($buckets, \@length_counts, 0, "Buckets", "Len");
702        $return .= _bucket_stats_formatted_bars($keys, \@key_depth, 1, "Keys", "Pos");
703    }
704    return $return
705}
706
707=item B<hv_store>
708
709  my $sv = 0;
710  hv_store(%hash,$key,$sv) or die "Failed to alias!";
711  $hash{$key} = 1;
712  print $sv; # prints 1
713
714Stores an alias to a variable in a hash instead of copying the value.
715
716=item B<hash_traversal_mask>
717
718As of Perl 5.18 every hash has its own hash traversal order, and this order
719changes every time a new element is inserted into the hash. This functionality
720is provided by maintaining an unsigned integer mask (U32) which is xor'ed
721with the actual bucket id during a traversal of the hash buckets using keys(),
722values() or each().
723
724You can use this subroutine to get and set the traversal mask for a specific
725hash. Setting the mask ensures that a given hash will produce the same key
726order. B<Note> that this does B<not> guarantee that B<two> hashes will produce
727the same key order for the same hash seed and traversal mask, items that
728collide into one bucket may have different orders regardless of this setting.
729
730=back
731
732=head2 Operating on references to hashes.
733
734Most subroutines documented in this module have equivalent versions
735that operate on references to hashes instead of native hashes.
736The following is a list of these subs. They are identical except
737in name and in that instead of taking a %hash they take a $hashref,
738and additionally are not prototyped.
739
740=over 4
741
742=item lock_ref_keys
743
744=item unlock_ref_keys
745
746=item lock_ref_keys_plus
747
748=item lock_ref_value
749
750=item unlock_ref_value
751
752=item lock_hashref
753
754=item unlock_hashref
755
756=item lock_hashref_recurse
757
758=item unlock_hashref_recurse
759
760=item hash_ref_unlocked
761
762=item legal_ref_keys
763
764=item hidden_ref_keys
765
766=back
767
768=head1 CAVEATS
769
770Note that the trapping of the restricted operations is not atomic:
771for example
772
773    eval { %hash = (illegal_key => 1) }
774
775leaves the C<%hash> empty rather than with its original contents.
776
777=head1 BUGS
778
779The interface exposed by this module is very close to the current
780implementation of restricted hashes. Over time it is expected that
781this behavior will be extended and the interface abstracted further.
782
783=head1 AUTHOR
784
785Michael G Schwern <schwern@pobox.com> on top of code by Nick
786Ing-Simmons and Jeffrey Friedl.
787
788hv_store() is from Array::RefElem, Copyright 2000 Gisle Aas.
789
790Additional code by Yves Orton.
791
792=head1 SEE ALSO
793
794L<Scalar::Util>, L<List::Util> and L<perlsec/"Algorithmic Complexity Attacks">.
795
796L<Hash::Util::FieldHash>.
797
798=cut
799
8001;
801